s4/pyauth: check ldb argument in py_user_session()
[sfrench/samba-autobuild/.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         struct dom_sid_buf buf;
354         const char *primary_group_dn;
355         DATA_BLOB primary_group_blob;
356         /* SID structures for the expanded group memberships */
357         struct dom_sid *sids = NULL;
358         unsigned int num_sids = 0, i;
359         struct dom_sid *domain_sid;
360         TALLOC_CTX *tmp_ctx;
361         struct ldb_message_element *el;
362
363         user_info_dc = talloc(mem_ctx, struct auth_user_info_dc);
364         NT_STATUS_HAVE_NO_MEMORY(user_info_dc);
365
366         tmp_ctx = talloc_new(user_info_dc);
367         if (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_dn = talloc_asprintf(
408                 tmp_ctx,
409                 "<SID=%s>",
410                 dom_sid_str_buf(&sids[PRIMARY_GROUP_SID_INDEX], &buf));
411         if (primary_group_dn == NULL) {
412                 TALLOC_FREE(user_info_dc);
413                 return NT_STATUS_NO_MEMORY;
414         }
415
416         primary_group_blob = data_blob_string_const(primary_group_dn);
417
418         /* Expands the primary group - this function takes in
419          * memberOf-like values, so we fake one up with the
420          * <SID=S-...> format of DN and then let it expand
421          * them, as long as they meet the filter - so only
422          * domain groups, not builtin groups
423          *
424          * The primary group is still treated specially, so we set the
425          * 'only childs' flag to true
426          */
427         status = dsdb_expand_nested_groups(sam_ctx, &primary_group_blob, true, filter,
428                                            user_info_dc, &sids, &num_sids);
429         if (!NT_STATUS_IS_OK(status)) {
430                 talloc_free(user_info_dc);
431                 return status;
432         }
433
434         /* Expands the additional groups */
435         el = ldb_msg_find_element(msg, "memberOf");
436         for (i = 0; el && i < el->num_values; i++) {
437                 /* This function takes in memberOf values and expands
438                  * them, as long as they meet the filter - so only
439                  * domain groups, not builtin groups */
440                 status = dsdb_expand_nested_groups(sam_ctx, &el->values[i], false, filter,
441                                                    user_info_dc, &sids, &num_sids);
442                 if (!NT_STATUS_IS_OK(status)) {
443                         talloc_free(user_info_dc);
444                         return status;
445                 }
446         }
447
448         user_info_dc->sids = sids;
449         user_info_dc->num_sids = num_sids;
450
451         user_info_dc->info = info = talloc_zero(user_info_dc, struct auth_user_info);
452         NT_STATUS_HAVE_NO_MEMORY(user_info_dc->info);
453
454         info->account_name = talloc_steal(info,
455                 ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL));
456
457         info->user_principal_name = talloc_steal(info,
458                 ldb_msg_find_attr_as_string(msg, "userPrincipalName", NULL));
459         if (info->user_principal_name == NULL && dns_domain_name != NULL) {
460                 info->user_principal_name = talloc_asprintf(info, "%s@%s",
461                                         info->account_name,
462                                         dns_domain_name);
463                 if (info->user_principal_name == NULL) {
464                         TALLOC_FREE(user_info_dc);
465                         return NT_STATUS_NO_MEMORY;
466                 }
467                 info->user_principal_constructed = true;
468         }
469
470         info->domain_name = talloc_strdup(info, domain_name);
471         if (info->domain_name == NULL) {
472                 TALLOC_FREE(user_info_dc);
473                 return NT_STATUS_NO_MEMORY;
474         }
475
476         if (dns_domain_name != NULL) {
477                 info->dns_domain_name = talloc_strdup(info, dns_domain_name);
478                 if (info->dns_domain_name == NULL) {
479                         TALLOC_FREE(user_info_dc);
480                         return NT_STATUS_NO_MEMORY;
481                 }
482         }
483
484         str = ldb_msg_find_attr_as_string(msg, "displayName", "");
485         info->full_name = talloc_strdup(info, str);
486         if (info->full_name == NULL) {
487                 TALLOC_FREE(user_info_dc);
488                 return NT_STATUS_NO_MEMORY;
489         }
490
491         str = ldb_msg_find_attr_as_string(msg, "scriptPath", "");
492         info->logon_script = talloc_strdup(info, str);
493         if (info->logon_script == NULL) {
494                 TALLOC_FREE(user_info_dc);
495                 return NT_STATUS_NO_MEMORY;
496         }
497
498         str = ldb_msg_find_attr_as_string(msg, "profilePath", "");
499         info->profile_path = talloc_strdup(info, str);
500         if (info->profile_path == NULL) {
501                 TALLOC_FREE(user_info_dc);
502                 return NT_STATUS_NO_MEMORY;
503         }
504
505         str = ldb_msg_find_attr_as_string(msg, "homeDirectory", "");
506         info->home_directory = talloc_strdup(info, str);
507         if (info->home_directory == NULL) {
508                 TALLOC_FREE(user_info_dc);
509                 return NT_STATUS_NO_MEMORY;
510         }
511
512         str = ldb_msg_find_attr_as_string(msg, "homeDrive", "");
513         info->home_drive = talloc_strdup(info, str);
514         if (info->home_drive == NULL) {
515                 TALLOC_FREE(user_info_dc);
516                 return NT_STATUS_NO_MEMORY;
517         }
518
519         info->logon_server = talloc_strdup(info, netbios_name);
520         if (info->logon_server == NULL) {
521                 TALLOC_FREE(user_info_dc);
522                 return NT_STATUS_NO_MEMORY;
523         }
524
525         info->last_logon = samdb_result_nttime(msg, "lastLogon", 0);
526         info->last_logoff = samdb_result_last_logoff(msg);
527         info->acct_expiry = samdb_result_account_expires(msg);
528         info->last_password_change = samdb_result_nttime(msg,
529                 "pwdLastSet", 0);
530         info->allow_password_change
531                 = samdb_result_allow_password_change(sam_ctx, mem_ctx, 
532                         domain_dn, msg, "pwdLastSet");
533         info->force_password_change = samdb_result_nttime(msg,
534                 "msDS-UserPasswordExpiryTimeComputed", 0);
535         info->logon_count = ldb_msg_find_attr_as_uint(msg, "logonCount", 0);
536         info->bad_password_count = ldb_msg_find_attr_as_uint(msg, "badPwdCount",
537                 0);
538
539         info->acct_flags = samdb_result_acct_flags(msg, "msDS-User-Account-Control-Computed");
540
541         user_info_dc->user_session_key = data_blob_talloc(user_info_dc,
542                                                          user_sess_key.data,
543                                                          user_sess_key.length);
544         if (user_sess_key.data) {
545                 if (user_info_dc->user_session_key.data == NULL) {
546                         TALLOC_FREE(user_info_dc);
547                         return NT_STATUS_NO_MEMORY;
548                 }
549         }
550         user_info_dc->lm_session_key = data_blob_talloc(user_info_dc,
551                                                        lm_sess_key.data,
552                                                        lm_sess_key.length);
553         if (lm_sess_key.data) {
554                 if (user_info_dc->lm_session_key.data == NULL) {
555                         TALLOC_FREE(user_info_dc);
556                         return NT_STATUS_NO_MEMORY;
557                 }
558         }
559
560         if (info->acct_flags & ACB_SVRTRUST) {
561                 /* the SID_NT_ENTERPRISE_DCS SID gets added into the
562                    PAC */
563                 user_info_dc->sids = talloc_realloc(user_info_dc,
564                                                    user_info_dc->sids,
565                                                    struct dom_sid,
566                                                    user_info_dc->num_sids+1);
567                 if (user_info_dc->sids == NULL) {
568                         TALLOC_FREE(user_info_dc);
569                         return NT_STATUS_NO_MEMORY;
570                 }
571                 user_info_dc->sids[user_info_dc->num_sids] = global_sid_Enterprise_DCs;
572                 user_info_dc->num_sids++;
573         }
574
575         if ((info->acct_flags & (ACB_PARTIAL_SECRETS_ACCOUNT | ACB_WSTRUST)) ==
576             (ACB_PARTIAL_SECRETS_ACCOUNT | ACB_WSTRUST)) {
577                 /* the DOMAIN_RID_ENTERPRISE_READONLY_DCS PAC */
578                 user_info_dc->sids = talloc_realloc(user_info_dc,
579                                                    user_info_dc->sids,
580                                                    struct dom_sid,
581                                                    user_info_dc->num_sids+1);
582                 if (user_info_dc->sids == NULL) {
583                         TALLOC_FREE(user_info_dc);
584                         return NT_STATUS_NO_MEMORY;
585                 }
586                 user_info_dc->sids[user_info_dc->num_sids] = *domain_sid;
587                 sid_append_rid(&user_info_dc->sids[user_info_dc->num_sids],
588                             DOMAIN_RID_ENTERPRISE_READONLY_DCS);
589                 user_info_dc->num_sids++;
590         }
591
592         info->authenticated = true;
593
594         talloc_free(tmp_ctx);
595         *_user_info_dc = user_info_dc;
596
597         return NT_STATUS_OK;
598 }
599
600 _PUBLIC_ NTSTATUS authsam_update_user_info_dc(TALLOC_CTX *mem_ctx,
601                         struct ldb_context *sam_ctx,
602                         struct auth_user_info_dc *user_info_dc)
603 {
604         char *filter = NULL;
605         NTSTATUS status;
606         uint32_t i;
607         uint32_t n = 0;
608
609         /*
610          * This function exists to expand group memberships
611          * in the local domain (forest), as the token
612          * may come from a different domain.
613          */
614
615         /*
616          * Filter out builtin groups from this token. We will search
617          * for builtin groups later.
618          */
619         status = authsam_domain_group_filter(mem_ctx, &filter);
620         if (!NT_STATUS_IS_OK(status)) {
621                 TALLOC_FREE(user_info_dc);
622                 return status;
623         }
624
625         /*
626          * We loop only over the existing number of
627          * sids.
628          */
629         n = user_info_dc->num_sids;
630         for (i = 0; i < n; i++) {
631                 struct dom_sid *sid = &user_info_dc->sids[i];
632                 struct dom_sid_buf sid_buf;
633                 char dn_str[sizeof(sid_buf.buf)*2];
634                 DATA_BLOB dn_blob = data_blob_null;
635
636                 snprintf(dn_str,
637                         sizeof(dn_str),
638                         "<SID=%s>",
639                         dom_sid_str_buf(sid, &sid_buf));
640                 dn_blob = data_blob_string_const(dn_str);
641
642                 /*
643                  * We already have the SID in the token, so set
644                  * 'only childs' flag to true and add all
645                  * groups which match the filter.
646                  */
647                 status = dsdb_expand_nested_groups(sam_ctx, &dn_blob,
648                                                    true, filter,
649                                                    user_info_dc,
650                                                    &user_info_dc->sids,
651                                                    &user_info_dc->num_sids);
652                 if (!NT_STATUS_IS_OK(status)) {
653                         return status;
654                 }
655         }
656
657         return NT_STATUS_OK;
658 }
659
660 NTSTATUS sam_get_results_principal(struct ldb_context *sam_ctx,
661                                    TALLOC_CTX *mem_ctx, const char *principal,
662                                    const char **attrs,
663                                    struct ldb_dn **domain_dn,
664                                    struct ldb_message **msg)
665 {                          
666         struct ldb_dn *user_dn;
667         NTSTATUS nt_status;
668         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
669         int ret;
670
671         if (!tmp_ctx) {
672                 return NT_STATUS_NO_MEMORY;
673         }
674
675         nt_status = crack_user_principal_name(sam_ctx, tmp_ctx, principal, 
676                                               &user_dn, domain_dn);
677         if (!NT_STATUS_IS_OK(nt_status)) {
678                 talloc_free(tmp_ctx);
679                 return nt_status;
680         }
681         
682         /* pull the user attributes */
683         ret = dsdb_search_one(sam_ctx, tmp_ctx, msg, user_dn,
684                               LDB_SCOPE_BASE, attrs,
685                               DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
686                               "(objectClass=*)");
687         if (ret != LDB_SUCCESS) {
688                 talloc_free(tmp_ctx);
689                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
690         }
691         talloc_steal(mem_ctx, *msg);
692         talloc_steal(mem_ctx, *domain_dn);
693         talloc_free(tmp_ctx);
694         
695         return NT_STATUS_OK;
696 }
697
698 /* Used in the gensec_gssapi and gensec_krb5 server-side code, where the PAC isn't available, and for tokenGroups in the DSDB stack.
699
700  Supply either a principal or a DN
701 */
702 NTSTATUS authsam_get_user_info_dc_principal(TALLOC_CTX *mem_ctx,
703                                            struct loadparm_context *lp_ctx,
704                                            struct ldb_context *sam_ctx,
705                                            const char *principal,
706                                            struct ldb_dn *user_dn,
707                                            struct auth_user_info_dc **user_info_dc)
708 {
709         NTSTATUS nt_status;
710         DATA_BLOB user_sess_key = data_blob(NULL, 0);
711         DATA_BLOB lm_sess_key = data_blob(NULL, 0);
712
713         struct ldb_message *msg;
714         struct ldb_dn *domain_dn;
715
716         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
717         if (!tmp_ctx) {
718                 return NT_STATUS_NO_MEMORY;
719         }
720
721         if (principal) {
722                 nt_status = sam_get_results_principal(sam_ctx, tmp_ctx, principal,
723                                                       user_attrs, &domain_dn, &msg);
724                 if (!NT_STATUS_IS_OK(nt_status)) {
725                         talloc_free(tmp_ctx);
726                         return nt_status;
727                 }
728         } else if (user_dn) {
729                 struct dom_sid *user_sid, *domain_sid;
730                 int ret;
731                 /* pull the user attributes */
732                 ret = dsdb_search_one(sam_ctx, tmp_ctx, &msg, user_dn,
733                                       LDB_SCOPE_BASE, user_attrs,
734                                       DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
735                                       "(objectClass=*)");
736                 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
737                         talloc_free(tmp_ctx);
738                         return NT_STATUS_NO_SUCH_USER;
739                 } else if (ret != LDB_SUCCESS) {
740                         talloc_free(tmp_ctx);
741                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
742                 }
743
744                 user_sid = samdb_result_dom_sid(msg, msg, "objectSid");
745
746                 nt_status = dom_sid_split_rid(tmp_ctx, user_sid, &domain_sid, NULL);
747                 if (!NT_STATUS_IS_OK(nt_status)) {
748                         return nt_status;
749                 }
750
751                 domain_dn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
752                                           "(&(objectSid=%s)(objectClass=domain))",
753                                             ldap_encode_ndr_dom_sid(tmp_ctx, domain_sid));
754                 if (!domain_dn) {
755                         struct dom_sid_buf buf;
756                         DEBUG(3, ("authsam_get_user_info_dc_principal: Failed to find domain with: SID %s\n",
757                                   dom_sid_str_buf(domain_sid, &buf)));
758                         return NT_STATUS_NO_SUCH_USER;
759                 }
760
761         } else {
762                 return NT_STATUS_INVALID_PARAMETER;
763         }
764
765         nt_status = authsam_make_user_info_dc(tmp_ctx, sam_ctx,
766                                              lpcfg_netbios_name(lp_ctx),
767                                              lpcfg_sam_name(lp_ctx),
768                                              lpcfg_sam_dnsname(lp_ctx),
769                                              domain_dn,
770                                              msg,
771                                              user_sess_key, lm_sess_key,
772                                              user_info_dc);
773         if (!NT_STATUS_IS_OK(nt_status)) {
774                 talloc_free(tmp_ctx);
775                 return nt_status;
776         }
777
778         talloc_steal(mem_ctx, *user_info_dc);
779         talloc_free(tmp_ctx);
780
781         return NT_STATUS_OK;
782 }
783
784 /*
785  * Returns the details for the Password Settings Object (PSO), if one applies
786  * the user.
787  */
788 static int authsam_get_user_pso(struct ldb_context *sam_ctx,
789                                 TALLOC_CTX *mem_ctx,
790                                 struct ldb_message *user_msg,
791                                 struct ldb_message **pso_msg)
792 {
793         const char *attrs[] = { "msDS-LockoutThreshold",
794                                 "msDS-LockoutObservationWindow",
795                                 NULL };
796         struct ldb_dn *pso_dn = NULL;
797         struct ldb_result *res = NULL;
798         int ret;
799
800         /* check if the user has a PSO that applies to it */
801         pso_dn = ldb_msg_find_attr_as_dn(sam_ctx, mem_ctx, user_msg,
802                                          "msDS-ResultantPSO");
803
804         if (pso_dn != NULL) {
805                 ret = dsdb_search_dn(sam_ctx, mem_ctx, &res, pso_dn, attrs, 0);
806                 if (ret != LDB_SUCCESS) {
807                         return ret;
808                 }
809
810                 *pso_msg = res->msgs[0];
811         }
812
813         return LDB_SUCCESS;
814 }
815
816 NTSTATUS authsam_update_bad_pwd_count(struct ldb_context *sam_ctx,
817                                       struct ldb_message *msg,
818                                       struct ldb_dn *domain_dn)
819 {
820         const char *attrs[] = { "lockoutThreshold",
821                                 "lockOutObservationWindow",
822                                 "lockoutDuration",
823                                 "pwdProperties",
824                                 NULL };
825         int ret;
826         NTSTATUS status;
827         struct ldb_result *domain_res;
828         struct ldb_message *msg_mod = NULL;
829         struct ldb_message *pso_msg = NULL;
830         TALLOC_CTX *mem_ctx;
831
832         mem_ctx = talloc_new(msg);
833         if (mem_ctx == NULL) {
834                 return NT_STATUS_NO_MEMORY;
835         }
836
837         ret = dsdb_search_dn(sam_ctx, mem_ctx, &domain_res, domain_dn, attrs, 0);
838         if (ret != LDB_SUCCESS) {
839                 TALLOC_FREE(mem_ctx);
840                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
841         }
842
843         ret = authsam_get_user_pso(sam_ctx, mem_ctx, msg, &pso_msg);
844         if (ret != LDB_SUCCESS) {
845
846                 /*
847                  * fallback to using the domain defaults so that we still
848                  * record the bad password attempt
849                  */
850                 DBG_ERR("Error (%d) checking PSO for %s",
851                         ret, ldb_dn_get_linearized(msg->dn));
852         }
853
854         status = dsdb_update_bad_pwd_count(mem_ctx, sam_ctx,
855                                            msg, domain_res->msgs[0], pso_msg,
856                                            &msg_mod);
857         if (!NT_STATUS_IS_OK(status)) {
858                 TALLOC_FREE(mem_ctx);
859                 return status;
860         }
861
862         if (msg_mod != NULL) {
863                 struct ldb_request *req;
864
865                 ret = ldb_build_mod_req(&req, sam_ctx, sam_ctx,
866                                         msg_mod,
867                                         NULL,
868                                         NULL,
869                                         ldb_op_default_callback,
870                                         NULL);
871                 if (ret != LDB_SUCCESS) {
872                         goto done;
873                 }
874
875                 ret = ldb_request_add_control(req,
876                                               DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE,
877                                               false, NULL);
878                 if (ret != LDB_SUCCESS) {
879                         talloc_free(req);
880                         goto done;
881                 }
882
883                 ret = dsdb_autotransaction_request(sam_ctx, req);
884                 talloc_free(req);
885         }
886
887 done:
888         if (ret != LDB_SUCCESS) {
889                 DEBUG(0, ("Failed to update badPwdCount, badPasswordTime or set lockoutTime on %s: %s\n",
890                           ldb_dn_get_linearized(msg_mod->dn), ldb_errstring(sam_ctx)));
891                 TALLOC_FREE(mem_ctx);
892                 return NT_STATUS_INTERNAL_ERROR;
893         }
894
895         TALLOC_FREE(mem_ctx);
896         return NT_STATUS_OK;
897 }
898
899
900 static NTSTATUS authsam_update_lastlogon_timestamp(struct ldb_context *sam_ctx,
901                                             struct ldb_message *msg_mod,
902                                             struct ldb_dn *domain_dn,
903                                             NTTIME old_timestamp,
904                                             NTTIME now)
905 {
906         /*
907          * We only set lastLogonTimestamp if the current value is older than
908          * now - msDS-LogonTimeSyncInterval days.
909          *
910          * msDS-LogonTimeSyncInterval is an int32_t number of days, while
911          * lastLogonTimestamp is in the 64 bit 100ns NTTIME format.
912          *
913          * The docs say: "the initial update, after the domain functional
914          * level is raised to DS_BEHAVIOR_WIN2003 or higher, is calculated as
915          * 14 days minus a random percentage of 5 days", but we aren't doing
916          * that. The blogosphere seems to think that this randomised update
917          * happens everytime, but [MS-ADA1] doesn't agree.
918          *
919          * Dochelp referred us to the following blog post:
920          * http://blogs.technet.com/b/askds/archive/2009/04/15/the-lastlogontimestamp-attribute-what-it-was-designed-for-and-how-it-works.aspx
921          *
922          * en msDS-LogonTimeSyncInterval is zero, the lastLogonTimestamp is
923          * not changed.
924          */
925         static const char *attrs[] = { "msDS-LogonTimeSyncInterval",
926                                         NULL };
927         int ret;
928         struct ldb_result *domain_res = NULL;
929         TALLOC_CTX *mem_ctx = NULL;
930         int32_t sync_interval;
931         NTTIME sync_interval_nt;
932
933         mem_ctx = talloc_new(msg_mod);
934         if (mem_ctx == NULL) {
935                 return NT_STATUS_NO_MEMORY;
936         }
937
938         ret = dsdb_search_dn(sam_ctx, mem_ctx, &domain_res, domain_dn, attrs,
939                              0);
940         if (ret != LDB_SUCCESS || domain_res->count != 1) {
941                 TALLOC_FREE(mem_ctx);
942                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
943         }
944
945         sync_interval = ldb_msg_find_attr_as_int(domain_res->msgs[0],
946                                                  "msDS-LogonTimeSyncInterval",
947                                                  14);
948         DEBUG(5, ("sync interval is %d\n", sync_interval));
949         if (sync_interval == 0){
950                 /*
951                  * Setting msDS-LogonTimeSyncInterval to zero is how you ask
952                  * that nothing happens here.
953                  */
954                 TALLOC_FREE(mem_ctx);
955                 return NT_STATUS_OK;
956         }
957         else if (sync_interval >= 5){
958                 /*
959                  * Subtract "a random percentage of 5" days. Presumably this
960                  * percentage is between 0 and 100, and modulus is accurate
961                  * enough.
962                  */
963                 uint32_t r = generate_random() % 6;
964                 sync_interval -= r;
965                 DEBUG(5, ("randomised sync interval is %d (-%d)\n", sync_interval, r));
966         }
967         /* In the case where sync_interval < 5 there is no randomisation */
968
969         sync_interval_nt = sync_interval * 24LL * 3600LL * 10000000LL;
970
971         DEBUG(5, ("old timestamp is %lld, threshold %lld, diff %lld\n",
972                   (long long int)old_timestamp,
973                   (long long int)(now - sync_interval_nt),
974                   (long long int)(old_timestamp - now + sync_interval_nt)));
975
976         if (old_timestamp > now){
977                 DEBUG(0, ("lastLogonTimestamp is in the future! (%lld > %lld)\n",
978                           (long long int)old_timestamp, (long long int)now));
979                 /* then what? */
980
981         } else if (old_timestamp < now - sync_interval_nt){
982                 DEBUG(5, ("updating lastLogonTimestamp to %lld\n",
983                           (long long int)now));
984
985                 /* The time has come to update lastLogonTimestamp */
986                 ret = samdb_msg_add_int64(sam_ctx, msg_mod, msg_mod,
987                                           "lastLogonTimestamp", now);
988
989                 if (ret != LDB_SUCCESS) {
990                         TALLOC_FREE(mem_ctx);
991                         return NT_STATUS_NO_MEMORY;
992                 }
993         }
994         TALLOC_FREE(mem_ctx);
995         return NT_STATUS_OK;
996 }
997
998 /****************************************************************************
999  Look for the specified user in the sam, return ldb result structures
1000 ****************************************************************************/
1001
1002 NTSTATUS authsam_search_account(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx,
1003                                          const char *account_name,
1004                                          struct ldb_dn *domain_dn,
1005                                          struct ldb_message **ret_msg)
1006 {
1007         int ret;
1008
1009         /* pull the user attributes */
1010         ret = dsdb_search_one(sam_ctx, mem_ctx, ret_msg, domain_dn, LDB_SCOPE_SUBTREE,
1011                               user_attrs,
1012                               DSDB_SEARCH_SHOW_EXTENDED_DN,
1013                               "(&(sAMAccountName=%s)(objectclass=user))",
1014                               ldb_binary_encode_string(mem_ctx, account_name));
1015         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
1016                 DEBUG(3,("sam_search_user: Couldn't find user [%s] in samdb, under %s\n",
1017                          account_name, ldb_dn_get_linearized(domain_dn)));
1018                 return NT_STATUS_NO_SUCH_USER;
1019         }
1020         if (ret != LDB_SUCCESS) {
1021                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1022         }
1023
1024         return NT_STATUS_OK;
1025 }
1026
1027
1028 /* Reset the badPwdCount to zero and update the lastLogon time. */
1029 NTSTATUS authsam_logon_success_accounting(struct ldb_context *sam_ctx,
1030                                           const struct ldb_message *msg,
1031                                           struct ldb_dn *domain_dn,
1032                                           bool interactive_or_kerberos,
1033                                           struct netr_SendToSamBase **send_to_sam)
1034 {
1035         int ret;
1036         NTSTATUS status;
1037         int badPwdCount;
1038         int dbBadPwdCount;
1039         int64_t lockoutTime;
1040         struct ldb_message *msg_mod;
1041         TALLOC_CTX *mem_ctx;
1042         struct timeval tv_now;
1043         NTTIME now;
1044         NTTIME lastLogonTimestamp;
1045         bool am_rodc = false;
1046
1047         mem_ctx = talloc_new(msg);
1048         if (mem_ctx == NULL) {
1049                 return NT_STATUS_NO_MEMORY;
1050         }
1051
1052         lockoutTime = ldb_msg_find_attr_as_int64(msg, "lockoutTime", 0);
1053         dbBadPwdCount = ldb_msg_find_attr_as_int(msg, "badPwdCount", 0);
1054         if (interactive_or_kerberos) {
1055                 badPwdCount = dbBadPwdCount;
1056         } else {
1057                 badPwdCount = samdb_result_effective_badPwdCount(sam_ctx, mem_ctx,
1058                                                                  domain_dn, msg);
1059         }
1060         lastLogonTimestamp =
1061                 ldb_msg_find_attr_as_int64(msg, "lastLogonTimestamp", 0);
1062
1063         DEBUG(5, ("lastLogonTimestamp is %lld\n",
1064                   (long long int)lastLogonTimestamp));
1065
1066         msg_mod = ldb_msg_new(mem_ctx);
1067         if (msg_mod == NULL) {
1068                 TALLOC_FREE(mem_ctx);
1069                 return NT_STATUS_NO_MEMORY;
1070         }
1071         msg_mod->dn = msg->dn;
1072
1073         if (lockoutTime != 0) {
1074                 /*
1075                  * This implies "badPwdCount" = 0, see samldb_lockout_time()
1076                  */
1077                 ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod, "lockoutTime", 0);
1078                 if (ret != LDB_SUCCESS) {
1079                         TALLOC_FREE(mem_ctx);
1080                         return NT_STATUS_NO_MEMORY;
1081                 }
1082         } else if (badPwdCount != 0) {
1083                 ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod, "badPwdCount", 0);
1084                 if (ret != LDB_SUCCESS) {
1085                         TALLOC_FREE(mem_ctx);
1086                         return NT_STATUS_NO_MEMORY;
1087                 }
1088         }
1089
1090         tv_now = timeval_current();
1091         now = timeval_to_nttime(&tv_now);
1092
1093         if (interactive_or_kerberos ||
1094             (badPwdCount != 0 && lockoutTime == 0)) {
1095                 ret = samdb_msg_add_int64(sam_ctx, msg_mod, msg_mod,
1096                                           "lastLogon", now);
1097                 if (ret != LDB_SUCCESS) {
1098                         TALLOC_FREE(mem_ctx);
1099                         return NT_STATUS_NO_MEMORY;
1100                 }
1101         }
1102
1103         if (interactive_or_kerberos) {
1104                 int logonCount;
1105
1106                 logonCount = ldb_msg_find_attr_as_int(msg, "logonCount", 0);
1107
1108                 logonCount += 1;
1109
1110                 ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod,
1111                                         "logonCount", logonCount);
1112                 if (ret != LDB_SUCCESS) {
1113                         TALLOC_FREE(mem_ctx);
1114                         return NT_STATUS_NO_MEMORY;
1115                 }
1116         } else {
1117                 /* Set an unset logonCount to 0 on first successful login */
1118                 if (ldb_msg_find_ldb_val(msg, "logonCount") == NULL) {
1119                         ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod,
1120                                                 "logonCount", 0);
1121                         if (ret != LDB_SUCCESS) {
1122                                 TALLOC_FREE(mem_ctx);
1123                                 return NT_STATUS_NO_MEMORY;
1124                         }
1125                 }
1126         }
1127
1128         ret = samdb_rodc(sam_ctx, &am_rodc);
1129         if (ret != LDB_SUCCESS) {
1130                 TALLOC_FREE(mem_ctx);
1131                 return NT_STATUS_INTERNAL_ERROR;
1132         }
1133
1134         if (!am_rodc) {
1135                 status = authsam_update_lastlogon_timestamp(sam_ctx, msg_mod, domain_dn,
1136                                                             lastLogonTimestamp, now);
1137                 if (!NT_STATUS_IS_OK(status)) {
1138                         TALLOC_FREE(mem_ctx);
1139                         return NT_STATUS_NO_MEMORY;
1140                 }
1141         } else {
1142                 /* Perform the (async) SendToSAM calls for MS-SAMS */
1143                 if (dbBadPwdCount != 0 && send_to_sam != NULL) {
1144                         struct netr_SendToSamBase *base_msg;
1145                         struct GUID guid = samdb_result_guid(msg, "objectGUID");
1146                         base_msg = talloc_zero(msg, struct netr_SendToSamBase);
1147
1148                         base_msg->message_type = SendToSamResetBadPasswordCount;
1149                         base_msg->message_size = 16;
1150                         base_msg->message.reset_bad_password.guid = guid;
1151                         *send_to_sam = base_msg;
1152                 }
1153         }
1154
1155         if (msg_mod->num_elements > 0) {
1156                 unsigned int i;
1157                 struct ldb_request *req;
1158
1159                 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1160                 for (i=0;i<msg_mod->num_elements;i++) {
1161                         msg_mod->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1162                 }
1163
1164                 ret = ldb_build_mod_req(&req, sam_ctx, sam_ctx,
1165                                         msg_mod,
1166                                         NULL,
1167                                         NULL,
1168                                         ldb_op_default_callback,
1169                                         NULL);
1170                 if (ret != LDB_SUCCESS) {
1171                         goto done;
1172                 }
1173
1174                 ret = ldb_request_add_control(req,
1175                                               DSDB_CONTROL_FORCE_RODC_LOCAL_CHANGE,
1176                                               false, NULL);
1177                 if (ret != LDB_SUCCESS) {
1178                         talloc_free(req);
1179                         goto done;
1180                 }
1181
1182                 ret = dsdb_autotransaction_request(sam_ctx, req);
1183                 talloc_free(req);
1184         }
1185
1186 done:
1187         if (ret != LDB_SUCCESS) {
1188                 DEBUG(0, ("Failed to set badPwdCount and lockoutTime "
1189                           "to 0 and/or  lastlogon to now (%lld) "
1190                           "%s: %s\n", (long long int)now,
1191                           ldb_dn_get_linearized(msg_mod->dn),
1192                           ldb_errstring(sam_ctx)));
1193                 TALLOC_FREE(mem_ctx);
1194                 return NT_STATUS_INTERNAL_ERROR;
1195         }
1196
1197         TALLOC_FREE(mem_ctx);
1198         return NT_STATUS_OK;
1199 }