dsdb: Avoid calculating the PSO multiple times
[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 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                                                                                                               
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 ****************************************************************************/
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
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
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         const char *primary_group_string;
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 (user_info_dc == 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(user_info_dc, 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_string = dom_sid_string(tmp_ctx, &sids[PRIMARY_GROUP_SID_INDEX]);
408         if (primary_group_string == NULL) {
409                 TALLOC_FREE(user_info_dc);
410                 return NT_STATUS_NO_MEMORY;
411         }
412
413         primary_group_dn = talloc_asprintf(tmp_ctx, "<SID=%s>", primary_group_string);
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                 char sid_buf[DOM_SID_STR_BUFLEN] = {0,};
636                 char dn_str[DOM_SID_STR_BUFLEN*2] = {0,};
637                 DATA_BLOB dn_blob = data_blob_null;
638                 int len;
639
640                 len = dom_sid_string_buf(sid, sid_buf, sizeof(sid_buf));
641                 if (len+1 > sizeof(sid_buf)) {
642                         return NT_STATUS_INVALID_SID;
643                 }
644                 snprintf(dn_str, sizeof(dn_str), "<SID=%s>", sid_buf);
645                 dn_blob = data_blob_string_const(dn_str);
646
647                 /*
648                  * We already have the SID in the token, so set
649                  * 'only childs' flag to true and add all
650                  * groups which match the filter.
651                  */
652                 status = dsdb_expand_nested_groups(sam_ctx, &dn_blob,
653                                                    true, filter,
654                                                    user_info_dc,
655                                                    &user_info_dc->sids,
656                                                    &user_info_dc->num_sids);
657                 if (!NT_STATUS_IS_OK(status)) {
658                         return status;
659                 }
660         }
661
662         return NT_STATUS_OK;
663 }
664
665 NTSTATUS sam_get_results_principal(struct ldb_context *sam_ctx,
666                                    TALLOC_CTX *mem_ctx, const char *principal,
667                                    const char **attrs,
668                                    struct ldb_dn **domain_dn,
669                                    struct ldb_message **msg)
670 {                          
671         struct ldb_dn *user_dn;
672         NTSTATUS nt_status;
673         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
674         int ret;
675
676         if (!tmp_ctx) {
677                 return NT_STATUS_NO_MEMORY;
678         }
679
680         nt_status = crack_user_principal_name(sam_ctx, tmp_ctx, principal, 
681                                               &user_dn, domain_dn);
682         if (!NT_STATUS_IS_OK(nt_status)) {
683                 talloc_free(tmp_ctx);
684                 return nt_status;
685         }
686         
687         /* pull the user attributes */
688         ret = dsdb_search_one(sam_ctx, tmp_ctx, msg, user_dn,
689                               LDB_SCOPE_BASE, attrs,
690                               DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
691                               "(objectClass=*)");
692         if (ret != LDB_SUCCESS) {
693                 talloc_free(tmp_ctx);
694                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
695         }
696         talloc_steal(mem_ctx, *msg);
697         talloc_steal(mem_ctx, *domain_dn);
698         talloc_free(tmp_ctx);
699         
700         return NT_STATUS_OK;
701 }
702
703 /* Used in the gensec_gssapi and gensec_krb5 server-side code, where the PAC isn't available, and for tokenGroups in the DSDB stack.
704
705  Supply either a principal or a DN
706 */
707 NTSTATUS authsam_get_user_info_dc_principal(TALLOC_CTX *mem_ctx,
708                                            struct loadparm_context *lp_ctx,
709                                            struct ldb_context *sam_ctx,
710                                            const char *principal,
711                                            struct ldb_dn *user_dn,
712                                            struct auth_user_info_dc **user_info_dc)
713 {
714         NTSTATUS nt_status;
715         DATA_BLOB user_sess_key = data_blob(NULL, 0);
716         DATA_BLOB lm_sess_key = data_blob(NULL, 0);
717
718         struct ldb_message *msg;
719         struct ldb_dn *domain_dn;
720
721         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
722         if (!tmp_ctx) {
723                 return NT_STATUS_NO_MEMORY;
724         }
725
726         if (principal) {
727                 nt_status = sam_get_results_principal(sam_ctx, tmp_ctx, principal,
728                                                       user_attrs, &domain_dn, &msg);
729                 if (!NT_STATUS_IS_OK(nt_status)) {
730                         talloc_free(tmp_ctx);
731                         return nt_status;
732                 }
733         } else if (user_dn) {
734                 struct dom_sid *user_sid, *domain_sid;
735                 int ret;
736                 /* pull the user attributes */
737                 ret = dsdb_search_one(sam_ctx, tmp_ctx, &msg, user_dn,
738                                       LDB_SCOPE_BASE, user_attrs,
739                                       DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
740                                       "(objectClass=*)");
741                 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
742                         talloc_free(tmp_ctx);
743                         return NT_STATUS_NO_SUCH_USER;
744                 } else if (ret != LDB_SUCCESS) {
745                         talloc_free(tmp_ctx);
746                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
747                 }
748
749                 user_sid = samdb_result_dom_sid(msg, msg, "objectSid");
750
751                 nt_status = dom_sid_split_rid(tmp_ctx, user_sid, &domain_sid, NULL);
752                 if (!NT_STATUS_IS_OK(nt_status)) {
753                         return nt_status;
754                 }
755
756                 domain_dn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
757                                           "(&(objectSid=%s)(objectClass=domain))",
758                                             ldap_encode_ndr_dom_sid(tmp_ctx, domain_sid));
759                 if (!domain_dn) {
760                         DEBUG(3, ("authsam_get_user_info_dc_principal: Failed to find domain with: SID %s\n",
761                                   dom_sid_string(tmp_ctx, domain_sid)));
762                         return NT_STATUS_NO_SUCH_USER;
763                 }
764
765         } else {
766                 return NT_STATUS_INVALID_PARAMETER;
767         }
768
769         nt_status = authsam_make_user_info_dc(tmp_ctx, sam_ctx,
770                                              lpcfg_netbios_name(lp_ctx),
771                                              lpcfg_sam_name(lp_ctx),
772                                              lpcfg_sam_dnsname(lp_ctx),
773                                              domain_dn,
774                                              msg,
775                                              user_sess_key, lm_sess_key,
776                                              user_info_dc);
777         if (!NT_STATUS_IS_OK(nt_status)) {
778                 talloc_free(tmp_ctx);
779                 return nt_status;
780         }
781
782         talloc_steal(mem_ctx, *user_info_dc);
783         talloc_free(tmp_ctx);
784
785         return NT_STATUS_OK;
786 }
787
788 /*
789  * Returns the details for the Password Settings Object (PSO), if one applies
790  * the user.
791  */
792 static int authsam_get_user_pso(struct ldb_context *sam_ctx,
793                                 TALLOC_CTX *mem_ctx,
794                                 struct ldb_message *user_msg,
795                                 struct ldb_message **pso_msg)
796 {
797         const char *attrs[] = { "msDS-LockoutThreshold",
798                                 "msDS-LockoutObservationWindow",
799                                 NULL };
800         struct ldb_dn *pso_dn = NULL;
801         struct ldb_result *res = NULL;
802         int ret;
803
804         /* check if the user has a PSO that applies to it */
805         pso_dn = ldb_msg_find_attr_as_dn(sam_ctx, mem_ctx, user_msg,
806                                          "msDS-ResultantPSO");
807
808         if (pso_dn != NULL) {
809                 ret = dsdb_search_dn(sam_ctx, mem_ctx, &res, pso_dn, attrs, 0);
810                 if (ret != LDB_SUCCESS) {
811                         return ret;
812                 }
813
814                 *pso_msg = res->msgs[0];
815         }
816
817         return LDB_SUCCESS;
818 }
819
820 NTSTATUS authsam_update_bad_pwd_count(struct ldb_context *sam_ctx,
821                                       struct ldb_message *msg,
822                                       struct ldb_dn *domain_dn)
823 {
824         const char *attrs[] = { "lockoutThreshold",
825                                 "lockOutObservationWindow",
826                                 "lockoutDuration",
827                                 "pwdProperties",
828                                 NULL };
829         int ret;
830         NTSTATUS status;
831         struct ldb_result *domain_res;
832         struct ldb_message *msg_mod = NULL;
833         struct ldb_message *pso_msg = NULL;
834         TALLOC_CTX *mem_ctx;
835
836         mem_ctx = talloc_new(msg);
837         if (mem_ctx == NULL) {
838                 return NT_STATUS_NO_MEMORY;
839         }
840
841         ret = dsdb_search_dn(sam_ctx, mem_ctx, &domain_res, domain_dn, attrs, 0);
842         if (ret != LDB_SUCCESS) {
843                 TALLOC_FREE(mem_ctx);
844                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
845         }
846
847         ret = authsam_get_user_pso(sam_ctx, mem_ctx, msg, &pso_msg);
848         if (ret != LDB_SUCCESS) {
849
850                 /*
851                  * fallback to using the domain defaults so that we still
852                  * record the bad password attempt
853                  */
854                 DBG_ERR("Error (%d) checking PSO for %s",
855                         ret, ldb_dn_get_linearized(msg->dn));
856         }
857
858         status = dsdb_update_bad_pwd_count(mem_ctx, sam_ctx,
859                                            msg, domain_res->msgs[0], pso_msg,
860                                            &msg_mod);
861         if (!NT_STATUS_IS_OK(status)) {
862                 TALLOC_FREE(mem_ctx);
863                 return status;
864         }
865
866         if (msg_mod != NULL) {
867                 struct ldb_request *req;
868
869                 ret = ldb_build_mod_req(&req, sam_ctx, sam_ctx,
870                                         msg_mod,
871                                         NULL,
872                                         NULL,
873                                         ldb_op_default_callback,
874                                         NULL);
875                 if (ret != LDB_SUCCESS) {
876                         goto done;
877                 }
878
879                 ret = ldb_request_add_control(req,
880                                               DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE,
881                                               false, NULL);
882                 if (ret != LDB_SUCCESS) {
883                         talloc_free(req);
884                         goto done;
885                 }
886
887                 ret = dsdb_autotransaction_request(sam_ctx, req);
888                 talloc_free(req);
889         }
890
891 done:
892         if (ret != LDB_SUCCESS) {
893                 DEBUG(0, ("Failed to update badPwdCount, badPasswordTime or set lockoutTime on %s: %s\n",
894                           ldb_dn_get_linearized(msg_mod->dn), ldb_errstring(sam_ctx)));
895                 TALLOC_FREE(mem_ctx);
896                 return NT_STATUS_INTERNAL_ERROR;
897         }
898
899         TALLOC_FREE(mem_ctx);
900         return NT_STATUS_OK;
901 }
902
903
904 static NTSTATUS authsam_update_lastlogon_timestamp(struct ldb_context *sam_ctx,
905                                             struct ldb_message *msg_mod,
906                                             struct ldb_dn *domain_dn,
907                                             NTTIME old_timestamp,
908                                             NTTIME now)
909 {
910         /*
911          * We only set lastLogonTimestamp if the current value is older than
912          * now - msDS-LogonTimeSyncInterval days.
913          *
914          * msDS-LogonTimeSyncInterval is an int32_t number of days, while
915          * lastLogonTimestamp is in the 64 bit 100ns NTTIME format.
916          *
917          * The docs say: "the initial update, after the domain functional
918          * level is raised to DS_BEHAVIOR_WIN2003 or higher, is calculated as
919          * 14 days minus a random percentage of 5 days", but we aren't doing
920          * that. The blogosphere seems to think that this randomised update
921          * happens everytime, but [MS-ADA1] doesn't agree.
922          *
923          * Dochelp referred us to the following blog post:
924          * http://blogs.technet.com/b/askds/archive/2009/04/15/the-lastlogontimestamp-attribute-what-it-was-designed-for-and-how-it-works.aspx
925          *
926          * en msDS-LogonTimeSyncInterval is zero, the lastLogonTimestamp is
927          * not changed.
928          */
929         static const char *attrs[] = { "msDS-LogonTimeSyncInterval",
930                                         NULL };
931         int ret;
932         struct ldb_result *domain_res = NULL;
933         TALLOC_CTX *mem_ctx = NULL;
934         int32_t sync_interval;
935         NTTIME sync_interval_nt;
936
937         mem_ctx = talloc_new(msg_mod);
938         if (mem_ctx == NULL) {
939                 return NT_STATUS_NO_MEMORY;
940         }
941
942         ret = dsdb_search_dn(sam_ctx, mem_ctx, &domain_res, domain_dn, attrs,
943                              0);
944         if (ret != LDB_SUCCESS || domain_res->count != 1) {
945                 TALLOC_FREE(mem_ctx);
946                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
947         }
948
949         sync_interval = ldb_msg_find_attr_as_int(domain_res->msgs[0],
950                                                  "msDS-LogonTimeSyncInterval",
951                                                  14);
952         DEBUG(5, ("sync interval is %d\n", sync_interval));
953         if (sync_interval == 0){
954                 /*
955                  * Setting msDS-LogonTimeSyncInterval to zero is how you ask
956                  * that nothing happens here.
957                  */
958                 TALLOC_FREE(mem_ctx);
959                 return NT_STATUS_OK;
960         }
961         else if (sync_interval >= 5){
962                 /*
963                  * Subtract "a random percentage of 5" days. Presumably this
964                  * percentage is between 0 and 100, and modulus is accurate
965                  * enough.
966                  */
967                 uint32_t r = generate_random() % 6;
968                 sync_interval -= r;
969                 DEBUG(5, ("randomised sync interval is %d (-%d)\n", sync_interval, r));
970         }
971         /* In the case where sync_interval < 5 there is no randomisation */
972
973         sync_interval_nt = sync_interval * 24LL * 3600LL * 10000000LL;
974
975         DEBUG(5, ("old timestamp is %lld, threshold %lld, diff %lld\n",
976                   (long long int)old_timestamp,
977                   (long long int)(now - sync_interval_nt),
978                   (long long int)(old_timestamp - now + sync_interval_nt)));
979
980         if (old_timestamp > now){
981                 DEBUG(0, ("lastLogonTimestamp is in the future! (%lld > %lld)\n",
982                           (long long int)old_timestamp, (long long int)now));
983                 /* then what? */
984
985         } else if (old_timestamp < now - sync_interval_nt){
986                 DEBUG(5, ("updating lastLogonTimestamp to %lld\n",
987                           (long long int)now));
988
989                 /* The time has come to update lastLogonTimestamp */
990                 ret = samdb_msg_add_int64(sam_ctx, msg_mod, msg_mod,
991                                           "lastLogonTimestamp", now);
992
993                 if (ret != LDB_SUCCESS) {
994                         TALLOC_FREE(mem_ctx);
995                         return NT_STATUS_NO_MEMORY;
996                 }
997         }
998         TALLOC_FREE(mem_ctx);
999         return NT_STATUS_OK;
1000 }
1001
1002 /****************************************************************************
1003  Look for the specified user in the sam, return ldb result structures
1004 ****************************************************************************/
1005
1006 NTSTATUS authsam_search_account(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx,
1007                                          const char *account_name,
1008                                          struct ldb_dn *domain_dn,
1009                                          struct ldb_message **ret_msg)
1010 {
1011         int ret;
1012
1013         /* pull the user attributes */
1014         ret = dsdb_search_one(sam_ctx, mem_ctx, ret_msg, domain_dn, LDB_SCOPE_SUBTREE,
1015                               user_attrs,
1016                               DSDB_SEARCH_SHOW_EXTENDED_DN,
1017                               "(&(sAMAccountName=%s)(objectclass=user))",
1018                               ldb_binary_encode_string(mem_ctx, account_name));
1019         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1020                 DEBUG(3,("sam_search_user: Couldn't find user [%s] in samdb, under %s\n",
1021                          account_name, ldb_dn_get_linearized(domain_dn)));
1022                 return NT_STATUS_NO_SUCH_USER;
1023         }
1024         if (ret != LDB_SUCCESS) {
1025                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1026         }
1027
1028         return NT_STATUS_OK;
1029 }
1030
1031
1032 /* Reset the badPwdCount to zero and update the lastLogon time. */
1033 NTSTATUS authsam_logon_success_accounting(struct ldb_context *sam_ctx,
1034                                           const struct ldb_message *msg,
1035                                           struct ldb_dn *domain_dn,
1036                                           bool interactive_or_kerberos,
1037                                           struct netr_SendToSamBase **send_to_sam)
1038 {
1039         int ret;
1040         NTSTATUS status;
1041         int badPwdCount;
1042         int dbBadPwdCount;
1043         int64_t lockoutTime;
1044         struct ldb_message *msg_mod;
1045         TALLOC_CTX *mem_ctx;
1046         struct timeval tv_now;
1047         NTTIME now;
1048         NTTIME lastLogonTimestamp;
1049         bool am_rodc = false;
1050
1051         mem_ctx = talloc_new(msg);
1052         if (mem_ctx == NULL) {
1053                 return NT_STATUS_NO_MEMORY;
1054         }
1055
1056         lockoutTime = ldb_msg_find_attr_as_int64(msg, "lockoutTime", 0);
1057         dbBadPwdCount = ldb_msg_find_attr_as_int(msg, "badPwdCount", 0);
1058         if (interactive_or_kerberos) {
1059                 badPwdCount = dbBadPwdCount;
1060         } else {
1061                 badPwdCount = samdb_result_effective_badPwdCount(sam_ctx, mem_ctx,
1062                                                                  domain_dn, msg);
1063         }
1064         lastLogonTimestamp =
1065                 ldb_msg_find_attr_as_int64(msg, "lastLogonTimestamp", 0);
1066
1067         DEBUG(5, ("lastLogonTimestamp is %lld\n",
1068                   (long long int)lastLogonTimestamp));
1069
1070         msg_mod = ldb_msg_new(mem_ctx);
1071         if (msg_mod == NULL) {
1072                 TALLOC_FREE(mem_ctx);
1073                 return NT_STATUS_NO_MEMORY;
1074         }
1075         msg_mod->dn = msg->dn;
1076
1077         if (lockoutTime != 0) {
1078                 /*
1079                  * This implies "badPwdCount" = 0, see samldb_lockout_time()
1080                  */
1081                 ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod, "lockoutTime", 0);
1082                 if (ret != LDB_SUCCESS) {
1083                         TALLOC_FREE(mem_ctx);
1084                         return NT_STATUS_NO_MEMORY;
1085                 }
1086         } else if (badPwdCount != 0) {
1087                 ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod, "badPwdCount", 0);
1088                 if (ret != LDB_SUCCESS) {
1089                         TALLOC_FREE(mem_ctx);
1090                         return NT_STATUS_NO_MEMORY;
1091                 }
1092         }
1093
1094         tv_now = timeval_current();
1095         now = timeval_to_nttime(&tv_now);
1096
1097         if (interactive_or_kerberos ||
1098             (badPwdCount != 0 && lockoutTime == 0)) {
1099                 ret = samdb_msg_add_int64(sam_ctx, msg_mod, msg_mod,
1100                                           "lastLogon", now);
1101                 if (ret != LDB_SUCCESS) {
1102                         TALLOC_FREE(mem_ctx);
1103                         return NT_STATUS_NO_MEMORY;
1104                 }
1105         }
1106
1107         if (interactive_or_kerberos) {
1108                 int logonCount;
1109
1110                 logonCount = ldb_msg_find_attr_as_int(msg, "logonCount", 0);
1111
1112                 logonCount += 1;
1113
1114                 ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod,
1115                                         "logonCount", logonCount);
1116                 if (ret != LDB_SUCCESS) {
1117                         TALLOC_FREE(mem_ctx);
1118                         return NT_STATUS_NO_MEMORY;
1119                 }
1120         } else {
1121                 /* Set an unset logonCount to 0 on first successful login */
1122                 if (ldb_msg_find_ldb_val(msg, "logonCount") == NULL) {
1123                         ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod,
1124                                                 "logonCount", 0);
1125                         if (ret != LDB_SUCCESS) {
1126                                 TALLOC_FREE(mem_ctx);
1127                                 return NT_STATUS_NO_MEMORY;
1128                         }
1129                 }
1130         }
1131
1132         ret = samdb_rodc(sam_ctx, &am_rodc);
1133         if (ret != LDB_SUCCESS) {
1134                 TALLOC_FREE(mem_ctx);
1135                 return NT_STATUS_INTERNAL_ERROR;
1136         }
1137
1138         if (!am_rodc) {
1139                 status = authsam_update_lastlogon_timestamp(sam_ctx, msg_mod, domain_dn,
1140                                                             lastLogonTimestamp, now);
1141                 if (!NT_STATUS_IS_OK(status)) {
1142                         TALLOC_FREE(mem_ctx);
1143                         return NT_STATUS_NO_MEMORY;
1144                 }
1145         } else {
1146                 /* Perform the (async) SendToSAM calls for MS-SAMS */
1147                 if (dbBadPwdCount != 0 && send_to_sam != NULL) {
1148                         struct netr_SendToSamBase *base_msg;
1149                         struct GUID guid = samdb_result_guid(msg, "objectGUID");
1150                         base_msg = talloc_zero(msg, struct netr_SendToSamBase);
1151
1152                         base_msg->message_type = SendToSamResetBadPasswordCount;
1153                         base_msg->message_size = 16;
1154                         base_msg->message.reset_bad_password.guid = guid;
1155                         *send_to_sam = base_msg;
1156                 }
1157         }
1158
1159         if (msg_mod->num_elements > 0) {
1160                 unsigned int i;
1161                 struct ldb_request *req;
1162
1163                 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1164                 for (i=0;i<msg_mod->num_elements;i++) {
1165                         msg_mod->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1166                 }
1167
1168                 ret = ldb_build_mod_req(&req, sam_ctx, sam_ctx,
1169                                         msg_mod,
1170                                         NULL,
1171                                         NULL,
1172                                         ldb_op_default_callback,
1173                                         NULL);
1174                 if (ret != LDB_SUCCESS) {
1175                         goto done;
1176                 }
1177
1178                 ret = ldb_request_add_control(req,
1179                                               DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE,
1180                                               false, NULL);
1181                 if (ret != LDB_SUCCESS) {
1182                         talloc_free(req);
1183                         goto done;
1184                 }
1185
1186                 ret = dsdb_autotransaction_request(sam_ctx, req);
1187                 talloc_free(req);
1188         }
1189
1190 done:
1191         if (ret != LDB_SUCCESS) {
1192                 DEBUG(0, ("Failed to set badPwdCount and lockoutTime "
1193                           "to 0 and/or  lastlogon to now (%lld) "
1194                           "%s: %s\n", (long long int)now,
1195                           ldb_dn_get_linearized(msg_mod->dn),
1196                           ldb_errstring(sam_ctx)));
1197                 TALLOC_FREE(mem_ctx);
1198                 return NT_STATUS_INTERNAL_ERROR;
1199         }
1200
1201         TALLOC_FREE(mem_ctx);
1202         return NT_STATUS_OK;
1203 }