s4:auth_sam: allow logons with an empty domain name
[sfrench/samba-autobuild/.git] / source4 / auth / ntlm / auth_sam.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Password and authentication handling
4    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2009
5    Copyright (C) Gerald Carter                             2003
6    Copyright (C) Stefan Metzmacher                         2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "system/time.h"
24 #include <ldb.h>
25 #include "libcli/ldap/ldap_ndr.h"
26 #include "libcli/security/security.h"
27 #include "auth/auth.h"
28 #include "../libcli/auth/ntlm_check.h"
29 #include "auth/ntlm/auth_proto.h"
30 #include "auth/auth_sam.h"
31 #include "dsdb/samdb/samdb.h"
32 #include "dsdb/common/util.h"
33 #include "param/param.h"
34 #include "librpc/gen_ndr/ndr_irpc_c.h"
35 #include "librpc/gen_ndr/ndr_winbind_c.h"
36 #include "lib/messaging/irpc.h"
37 #include "libcli/auth/libcli_auth.h"
38 #include "libds/common/roles.h"
39
40 NTSTATUS auth_sam_init(void);
41
42 extern const char *user_attrs[];
43 extern const char *domain_ref_attrs[];
44
45 /****************************************************************************
46  Do a specific test for an smb password being correct, given a smb_password and
47  the lanman and NT responses.
48 ****************************************************************************/
49 static NTSTATUS authsam_password_ok(struct auth4_context *auth_context,
50                                     TALLOC_CTX *mem_ctx,
51                                     uint16_t acct_flags,
52                                     const struct samr_Password *lm_pwd, 
53                                     const struct samr_Password *nt_pwd,
54                                     const struct auth_usersupplied_info *user_info, 
55                                     DATA_BLOB *user_sess_key, 
56                                     DATA_BLOB *lm_sess_key)
57 {
58         NTSTATUS status;
59
60         switch (user_info->password_state) {
61         case AUTH_PASSWORD_PLAIN: 
62         {
63                 const struct auth_usersupplied_info *user_info_temp;    
64                 status = encrypt_user_info(mem_ctx, auth_context, 
65                                            AUTH_PASSWORD_HASH, 
66                                            user_info, &user_info_temp);
67                 if (!NT_STATUS_IS_OK(status)) {
68                         DEBUG(1, ("Failed to convert plaintext password to password HASH: %s\n", nt_errstr(status)));
69                         return status;
70                 }
71                 user_info = user_info_temp;
72
73                 /*fall through*/
74         }
75         case AUTH_PASSWORD_HASH:
76                 *lm_sess_key = data_blob(NULL, 0);
77                 *user_sess_key = data_blob(NULL, 0);
78                 status = hash_password_check(mem_ctx, 
79                                              lpcfg_lanman_auth(auth_context->lp_ctx),
80                                              user_info->password.hash.lanman,
81                                              user_info->password.hash.nt,
82                                              user_info->mapped.account_name,
83                                              lm_pwd, nt_pwd);
84                 NT_STATUS_NOT_OK_RETURN(status);
85                 break;
86                 
87         case AUTH_PASSWORD_RESPONSE:
88                 status = ntlm_password_check(mem_ctx, 
89                                              lpcfg_lanman_auth(auth_context->lp_ctx),
90                                                  lpcfg_ntlm_auth(auth_context->lp_ctx),
91                                              user_info->logon_parameters, 
92                                              &auth_context->challenge.data, 
93                                              &user_info->password.response.lanman, 
94                                              &user_info->password.response.nt,
95                                              user_info->mapped.account_name,
96                                              user_info->client.account_name, 
97                                              user_info->client.domain_name, 
98                                              lm_pwd, nt_pwd,
99                                              user_sess_key, lm_sess_key);
100                 NT_STATUS_NOT_OK_RETURN(status);
101                 break;
102         }
103
104         return NT_STATUS_OK;
105 }
106
107 static void auth_sam_trigger_zero_password(TALLOC_CTX *mem_ctx,
108                                            struct imessaging_context *msg_ctx,
109                                            struct tevent_context *event_ctx,
110                                            struct netr_SendToSamBase *send_to_sam)
111 {
112         struct dcerpc_binding_handle *irpc_handle;
113         struct winbind_SendToSam r;
114         struct tevent_req *req;
115         TALLOC_CTX *tmp_ctx;
116
117         tmp_ctx = talloc_new(mem_ctx);
118         if (tmp_ctx == NULL) {
119                 return;
120         }
121
122         irpc_handle = irpc_binding_handle_by_name(tmp_ctx, msg_ctx,
123                                                   "winbind_server",
124                                                   &ndr_table_winbind);
125         if (irpc_handle == NULL) {
126                 DEBUG(1,(__location__ ": Unable to get binding handle for winbind\n"));
127                 TALLOC_FREE(tmp_ctx);
128                 return;
129         }
130
131         r.in.message = *send_to_sam;
132
133         /*
134          * This seem to rely on the current IRPC implementation,
135          * which delivers the message in the _send function.
136          *
137          * TODO: we need a ONE_WAY IRPC handle and register
138          * a callback and wait for it to be triggered!
139          */
140         req = dcerpc_winbind_SendToSam_r_send(tmp_ctx,
141                                               event_ctx,
142                                               irpc_handle,
143                                               &r);
144
145         /* we aren't interested in a reply */
146         talloc_free(req);
147         TALLOC_FREE(tmp_ctx);
148
149 }
150
151 /*
152   send a message to the drepl server telling it to initiate a
153   REPL_SECRET getncchanges extended op to fetch the users secrets
154  */
155 static void auth_sam_trigger_repl_secret(TALLOC_CTX *mem_ctx,
156                                          struct imessaging_context *msg_ctx,
157                                          struct tevent_context *event_ctx,
158                                          struct ldb_dn *user_dn)
159 {
160         struct dcerpc_binding_handle *irpc_handle;
161         struct drepl_trigger_repl_secret r;
162         struct tevent_req *req;
163         TALLOC_CTX *tmp_ctx;
164
165         tmp_ctx = talloc_new(mem_ctx);
166         if (tmp_ctx == NULL) {
167                 return;
168         }
169
170         irpc_handle = irpc_binding_handle_by_name(tmp_ctx, msg_ctx,
171                                                   "dreplsrv",
172                                                   &ndr_table_irpc);
173         if (irpc_handle == NULL) {
174                 DEBUG(1,(__location__ ": Unable to get binding handle for dreplsrv\n"));
175                 TALLOC_FREE(tmp_ctx);
176                 return;
177         }
178
179         r.in.user_dn = ldb_dn_get_linearized(user_dn);
180
181         /*
182          * This seem to rely on the current IRPC implementation,
183          * which delivers the message in the _send function.
184          *
185          * TODO: we need a ONE_WAY IRPC handle and register
186          * a callback and wait for it to be triggered!
187          */
188         req = dcerpc_drepl_trigger_repl_secret_r_send(tmp_ctx,
189                                                       event_ctx,
190                                                       irpc_handle,
191                                                       &r);
192
193         /* we aren't interested in a reply */
194         talloc_free(req);
195         TALLOC_FREE(tmp_ctx);
196 }
197
198
199 /*
200  * Check that a password is OK, and update badPwdCount if required.
201  */
202
203 static NTSTATUS authsam_password_check_and_record(struct auth4_context *auth_context,
204                                                   TALLOC_CTX *mem_ctx,
205                                                   struct ldb_dn *domain_dn,
206                                                   struct ldb_message *msg,
207                                                   uint16_t acct_flags,
208                                                   const struct auth_usersupplied_info *user_info,
209                                                   DATA_BLOB *user_sess_key,
210                                                   DATA_BLOB *lm_sess_key,
211                                                   bool *authoritative)
212 {
213         NTSTATUS nt_status;
214         NTSTATUS auth_status;
215         TALLOC_CTX *tmp_ctx;
216         int i, ret;
217         int history_len = 0;
218         struct ldb_context *sam_ctx = auth_context->sam_ctx;
219         const char * const attrs[] = { "pwdHistoryLength", NULL };
220         struct ldb_message *dom_msg;
221         struct samr_Password *lm_pwd;
222         struct samr_Password *nt_pwd;
223         bool am_rodc;
224
225         tmp_ctx = talloc_new(mem_ctx);
226         if (tmp_ctx == NULL) {
227                 return NT_STATUS_NO_MEMORY;
228         }
229
230         /*
231          * This call does more than what it appears to do, it also
232          * checks for the account lockout.
233          *
234          * It is done here so that all parts of Samba that read the
235          * password refuse to even operate on it if the account is
236          * locked out, to avoid mistakes like CVE-2013-4496.
237          */
238         nt_status = samdb_result_passwords(tmp_ctx, auth_context->lp_ctx,
239                                            msg, &lm_pwd, &nt_pwd);
240         if (!NT_STATUS_IS_OK(nt_status)) {
241                 TALLOC_FREE(tmp_ctx);
242                 return nt_status;
243         }
244
245         if (lm_pwd == NULL && nt_pwd == NULL) {
246                 if (samdb_rodc(auth_context->sam_ctx, &am_rodc) == LDB_SUCCESS && am_rodc) {
247                         /*
248                          * we don't have passwords for this
249                          * account. We are an RODC, and this account
250                          * may be one for which we either are denied
251                          * REPL_SECRET replication or we haven't yet
252                          * done the replication. We return
253                          * NT_STATUS_NOT_IMPLEMENTED which tells the
254                          * auth code to try the next authentication
255                          * mechanism. We also send a message to our
256                          * drepl server to tell it to try and
257                          * replicate the secrets for this account.
258                          *
259                          * TODO: Should we only trigger this is detected
260                          * there's a chance that the password might be
261                          * replicated, we should be able to detect this
262                          * based on msDS-NeverRevealGroup.
263                          */
264                         auth_sam_trigger_repl_secret(auth_context,
265                                                      auth_context->msg_ctx,
266                                                      auth_context->event_ctx,
267                                                      msg->dn);
268                         TALLOC_FREE(tmp_ctx);
269                         return NT_STATUS_NOT_IMPLEMENTED;
270                 }
271         }
272
273         auth_status = authsam_password_ok(auth_context, tmp_ctx,
274                                           acct_flags,
275                                           lm_pwd, nt_pwd,
276                                           user_info,
277                                           user_sess_key, lm_sess_key);
278         if (NT_STATUS_IS_OK(auth_status)) {
279                 if (user_sess_key->data) {
280                         talloc_steal(mem_ctx, user_sess_key->data);
281                 }
282                 if (lm_sess_key->data) {
283                         talloc_steal(mem_ctx, lm_sess_key->data);
284                 }
285                 TALLOC_FREE(tmp_ctx);
286                 return NT_STATUS_OK;
287         }
288         *user_sess_key = data_blob_null;
289         *lm_sess_key = data_blob_null;
290
291         if (!NT_STATUS_EQUAL(auth_status, NT_STATUS_WRONG_PASSWORD)) {
292                 TALLOC_FREE(tmp_ctx);
293                 return auth_status;
294         }
295
296         /*
297          * We only continue if this was a wrong password
298          * and we'll always return NT_STATUS_WRONG_PASSWORD
299          * no matter what error happens.
300          */
301
302         /* pull the domain password property attributes */
303         ret = dsdb_search_one(sam_ctx, tmp_ctx, &dom_msg, domain_dn, LDB_SCOPE_BASE,
304                               attrs, 0, "objectClass=domain");
305         if (ret == LDB_SUCCESS) {
306                 history_len = ldb_msg_find_attr_as_uint(dom_msg, "pwdHistoryLength", 0);
307         } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
308                 DEBUG(3,("Couldn't find domain %s: %s!\n",
309                          ldb_dn_get_linearized(domain_dn),
310                          ldb_errstring(sam_ctx)));
311         } else {
312                 DEBUG(3,("error finding domain %s: %s!\n",
313                          ldb_dn_get_linearized(domain_dn),
314                          ldb_errstring(sam_ctx)));
315         }
316
317         for (i = 1; i < MIN(history_len, 3); i++) {
318                 struct samr_Password zero_string_hash;
319                 struct samr_Password zero_string_des_hash;
320                 struct samr_Password *nt_history_pwd = NULL;
321                 struct samr_Password *lm_history_pwd = NULL;
322                 NTTIME pwdLastSet;
323                 struct timeval tv_now;
324                 NTTIME now;
325                 int allowed_period_mins;
326                 NTTIME allowed_period;
327
328                 nt_status = samdb_result_passwords_from_history(tmp_ctx,
329                                                         auth_context->lp_ctx,
330                                                         msg, i,
331                                                         &lm_history_pwd,
332                                                         &nt_history_pwd);
333                 if (!NT_STATUS_IS_OK(nt_status)) {
334                         /*
335                          * If we don't find element 'i' we won't find
336                          * 'i+1' ...
337                          */
338                         break;
339                 }
340
341                 /*
342                  * We choose to avoid any issues
343                  * around different LM and NT history
344                  * lengths by only checking the NT
345                  * history
346                  */
347                 if (nt_history_pwd == NULL) {
348                         /*
349                          * If we don't find element 'i' we won't find
350                          * 'i+1' ...
351                          */
352                         break;
353                 }
354
355                 /* Skip over all-zero hashes in the history */
356                 if (all_zero(nt_history_pwd->hash,
357                              sizeof(nt_history_pwd->hash))) {
358                         continue;
359                 }
360
361                 /*
362                  * This looks odd, but the password_hash module writes this in if
363                  * (somehow) we didn't have an old NT hash
364                  */
365
366                 E_md4hash("", zero_string_hash.hash);
367                 if (memcmp(nt_history_pwd->hash, zero_string_hash.hash, 16) == 0) {
368                         continue;
369                 }
370
371                 E_deshash("", zero_string_des_hash.hash);
372                 if (!lm_history_pwd || memcmp(lm_history_pwd->hash, zero_string_des_hash.hash, 16) == 0) {
373                         lm_history_pwd = NULL;
374                 }
375
376                 auth_status = authsam_password_ok(auth_context, tmp_ctx,
377                                                   acct_flags,
378                                                   lm_history_pwd,
379                                                   nt_history_pwd,
380                                                   user_info,
381                                                   user_sess_key,
382                                                   lm_sess_key);
383                 if (!NT_STATUS_IS_OK(auth_status)) {
384                         /*
385                          * If this was not a correct password, try the next
386                          * one from the history
387                          */
388                         *user_sess_key = data_blob_null;
389                         *lm_sess_key = data_blob_null;
390                         continue;
391                 }
392
393                 if (i != 1) {
394                         /*
395                          * The authentication was OK, but not against
396                          * the previous password, which is stored at index 1.
397                          *
398                          * We just return the original wrong password.
399                          * This skips the update of the bad pwd count,
400                          * because this is almost certainly user error
401                          * (or automatic login on a computer using a cached
402                          * password from before the password change),
403                          * not an attack.
404                          */
405                         TALLOC_FREE(tmp_ctx);
406                         return NT_STATUS_WRONG_PASSWORD;
407                 }
408
409                 if (user_info->password_state != AUTH_PASSWORD_RESPONSE) {
410                         /*
411                          * The authentication was OK against the previous password,
412                          * but it's not a NTLM network authentication.
413                          *
414                          * We just return the original wrong password.
415                          * This skips the update of the bad pwd count,
416                          * because this is almost certainly user error
417                          * (or automatic login on a computer using a cached
418                          * password from before the password change),
419                          * not an attack.
420                          */
421                         TALLOC_FREE(tmp_ctx);
422                         return NT_STATUS_WRONG_PASSWORD;
423                 }
424
425                 /*
426                  * If the password was OK, it's a NTLM network authentication
427                  * and it was the previous password.
428                  *
429                  * Now we see if it is within the grace period,
430                  * so that we don't break cached sessions on other computers
431                  * before the user can lock and unlock their other screens
432                  * (resetting their cached password).
433                  *
434                  * See http://support.microsoft.com/kb/906305
435                  * OldPasswordAllowedPeriod ("old password allowed period")
436                  * is specified in minutes. The default is 60.
437                  */
438                 allowed_period_mins = lpcfg_old_password_allowed_period(auth_context->lp_ctx);
439                 /*
440                  * NTTIME uses 100ns units
441                  */
442                 allowed_period = allowed_period_mins * 60 * 1000*1000*10;
443                 pwdLastSet = samdb_result_nttime(msg, "pwdLastSet", 0);
444                 tv_now = timeval_current();
445                 now = timeval_to_nttime(&tv_now);
446
447                 if (now < pwdLastSet) {
448                         /*
449                          * time jump?
450                          *
451                          * We just return the original wrong password.
452                          * This skips the update of the bad pwd count,
453                          * because this is almost certainly user error
454                          * (or automatic login on a computer using a cached
455                          * password from before the password change),
456                          * not an attack.
457                          */
458                         TALLOC_FREE(tmp_ctx);
459                         return NT_STATUS_WRONG_PASSWORD;
460                 }
461
462                 if ((now - pwdLastSet) >= allowed_period) {
463                         /*
464                          * The allowed period is over.
465                          *
466                          * We just return the original wrong password.
467                          * This skips the update of the bad pwd count,
468                          * because this is almost certainly user error
469                          * (or automatic login on a computer using a cached
470                          * password from before the password change),
471                          * not an attack.
472                          */
473                         TALLOC_FREE(tmp_ctx);
474                         return NT_STATUS_WRONG_PASSWORD;
475                 }
476
477                 /*
478                  * We finally allow the authentication with the
479                  * previous password within the allowed period.
480                  */
481                 if (user_sess_key->data) {
482                         talloc_steal(mem_ctx, user_sess_key->data);
483                 }
484                 if (lm_sess_key->data) {
485                         talloc_steal(mem_ctx, lm_sess_key->data);
486                 }
487
488                 TALLOC_FREE(tmp_ctx);
489                 return auth_status;
490         }
491
492         /*
493          * If we are not in the allowed period or match an old password,
494          * we didn't return early. Now update the badPwdCount et al.
495          */
496         nt_status = authsam_update_bad_pwd_count(auth_context->sam_ctx,
497                                                  msg, domain_dn);
498         if (!NT_STATUS_IS_OK(nt_status)) {
499                 /*
500                  * We need to return the original
501                  * NT_STATUS_WRONG_PASSWORD error, so there isn't
502                  * anything more we can do than write something into
503                  * the log
504                  */
505                 DEBUG(0, ("Failed to note bad password for user [%s]: %s\n",
506                           user_info->mapped.account_name,
507                           nt_errstr(nt_status)));
508         }
509
510         if (samdb_rodc(auth_context->sam_ctx, &am_rodc) == LDB_SUCCESS && am_rodc) {
511                 *authoritative = false;
512         }
513
514         TALLOC_FREE(tmp_ctx);
515         return NT_STATUS_WRONG_PASSWORD;
516 }
517
518 static NTSTATUS authsam_authenticate(struct auth4_context *auth_context,
519                                      TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx,
520                                      struct ldb_dn *domain_dn,
521                                      struct ldb_message *msg,
522                                      const struct auth_usersupplied_info *user_info,
523                                      DATA_BLOB *user_sess_key, DATA_BLOB *lm_sess_key,
524                                      bool *authoritative)
525 {
526         NTSTATUS nt_status;
527         bool interactive = (user_info->password_state == AUTH_PASSWORD_HASH);
528         uint32_t acct_flags = samdb_result_acct_flags(msg, NULL);
529         struct netr_SendToSamBase *send_to_sam = NULL;
530         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
531         if (!tmp_ctx) {
532                 return NT_STATUS_NO_MEMORY;
533         }
534
535         /* You can only do an interactive login to normal accounts */
536         if (user_info->flags & USER_INFO_INTERACTIVE_LOGON) {
537                 if (!(acct_flags & ACB_NORMAL)) {
538                         TALLOC_FREE(tmp_ctx);
539                         return NT_STATUS_NO_SUCH_USER;
540                 }
541                 if (acct_flags & ACB_SMARTCARD_REQUIRED) {
542                         if (acct_flags & ACB_DISABLED) {
543                                 DEBUG(2,("authsam_authenticate: Account for user '%s' "
544                                          "was disabled.\n",
545                                          user_info->mapped.account_name));
546                                 TALLOC_FREE(tmp_ctx);
547                                 return NT_STATUS_ACCOUNT_DISABLED;
548                         }
549                         DEBUG(2,("authsam_authenticate: Account for user '%s' "
550                                  "requires interactive smartcard logon.\n",
551                                  user_info->mapped.account_name));
552                         TALLOC_FREE(tmp_ctx);
553                         return NT_STATUS_SMARTCARD_LOGON_REQUIRED;
554                 }
555         }
556
557         nt_status = authsam_password_check_and_record(auth_context, tmp_ctx,
558                                                       domain_dn, msg, acct_flags,
559                                                       user_info,
560                                                       user_sess_key, lm_sess_key,
561                                                       authoritative);
562         if (!NT_STATUS_IS_OK(nt_status)) {
563                 TALLOC_FREE(tmp_ctx);
564                 return nt_status;
565         }
566
567         nt_status = authsam_account_ok(tmp_ctx, auth_context->sam_ctx,
568                                        user_info->logon_parameters,
569                                        domain_dn,
570                                        msg,
571                                        user_info->workstation_name,
572                                        user_info->mapped.account_name,
573                                        false, false);
574         if (!NT_STATUS_IS_OK(nt_status)) {
575                 TALLOC_FREE(tmp_ctx);
576                 return nt_status;
577         }
578
579         nt_status = authsam_logon_success_accounting(auth_context->sam_ctx,
580                                                      msg, domain_dn,
581                                                      interactive,
582                                                      &send_to_sam);
583
584         if (send_to_sam != NULL) {
585                 auth_sam_trigger_zero_password(tmp_ctx,
586                                                auth_context->msg_ctx,
587                                                auth_context->event_ctx,
588                                                send_to_sam);
589         }
590
591         if (!NT_STATUS_IS_OK(nt_status)) {
592                 TALLOC_FREE(tmp_ctx);
593                 return nt_status;
594         }
595
596         if (user_sess_key && user_sess_key->data) {
597                 talloc_steal(mem_ctx, user_sess_key->data);
598         }
599         if (lm_sess_key && lm_sess_key->data) {
600                 talloc_steal(mem_ctx, lm_sess_key->data);
601         }
602
603         TALLOC_FREE(tmp_ctx);
604         return nt_status;
605 }
606
607
608
609 static NTSTATUS authsam_check_password_internals(struct auth_method_context *ctx,
610                                                  TALLOC_CTX *mem_ctx,
611                                                  const struct auth_usersupplied_info *user_info, 
612                                                  struct auth_user_info_dc **user_info_dc,
613                                                  bool *authoritative)
614 {
615         NTSTATUS nt_status;
616         const char *account_name = user_info->mapped.account_name;
617         struct ldb_message *msg;
618         struct ldb_dn *domain_dn;
619         DATA_BLOB user_sess_key, lm_sess_key;
620         TALLOC_CTX *tmp_ctx;
621         const char *p = NULL;
622
623         if (ctx->auth_ctx->sam_ctx == NULL) {
624                 DEBUG(0, ("No SAM available, cannot log in users\n"));
625                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
626         }
627
628         if (!account_name || !*account_name) {
629                 /* 'not for me' */
630                 return NT_STATUS_NOT_IMPLEMENTED;
631         }
632
633         tmp_ctx = talloc_new(mem_ctx);
634         if (!tmp_ctx) {
635                 return NT_STATUS_NO_MEMORY;
636         }
637
638         domain_dn = ldb_get_default_basedn(ctx->auth_ctx->sam_ctx);
639         if (domain_dn == NULL) {
640                 talloc_free(tmp_ctx);
641                 return NT_STATUS_NO_SUCH_DOMAIN;
642         }
643
644         p = strchr_m(account_name, '@');
645         if (p != NULL) {
646                 const char *nt4_domain = NULL;
647                 const char *nt4_account = NULL;
648                 bool is_my_domain = false;
649
650                 nt_status = crack_name_to_nt4_name(mem_ctx,
651                                                    ctx->auth_ctx->sam_ctx,
652                                                    /*
653                                                     * DRSUAPI_DS_NAME_FORMAT_UPN_FOR_LOGON ?
654                                                     */
655                                                    DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
656                                                    account_name,
657                                                    &nt4_domain, &nt4_account);
658                 if (!NT_STATUS_IS_OK(nt_status)) {
659                         talloc_free(tmp_ctx);
660                         return NT_STATUS_NO_SUCH_USER;
661                 }
662
663                 is_my_domain = lpcfg_is_mydomain(ctx->auth_ctx->lp_ctx, nt4_domain);
664                 if (!is_my_domain) {
665                         /*
666                          * This is a user within our forest,
667                          * but in a different domain,
668                          * we're not authoritative
669                          */
670                         talloc_free(tmp_ctx);
671                         return NT_STATUS_NOT_IMPLEMENTED;
672                 }
673
674                 /*
675                  * Let's use the NT4 account name for the lookup.
676                  */
677                 account_name = nt4_account;
678         }
679
680         nt_status = authsam_search_account(tmp_ctx, ctx->auth_ctx->sam_ctx, account_name, domain_dn, &msg);
681         if (!NT_STATUS_IS_OK(nt_status)) {
682                 talloc_free(tmp_ctx);
683                 return nt_status;
684         }
685
686         nt_status = authsam_authenticate(ctx->auth_ctx, tmp_ctx, ctx->auth_ctx->sam_ctx, domain_dn, msg, user_info,
687                                          &user_sess_key, &lm_sess_key, authoritative);
688         if (!NT_STATUS_IS_OK(nt_status)) {
689                 talloc_free(tmp_ctx);
690                 return nt_status;
691         }
692
693         nt_status = authsam_make_user_info_dc(tmp_ctx, ctx->auth_ctx->sam_ctx,
694                                              lpcfg_netbios_name(ctx->auth_ctx->lp_ctx),
695                                              lpcfg_sam_name(ctx->auth_ctx->lp_ctx),
696                                              lpcfg_sam_dnsname(ctx->auth_ctx->lp_ctx),
697                                              domain_dn,
698                                              msg,
699                                              user_sess_key, lm_sess_key,
700                                              user_info_dc);
701         if (!NT_STATUS_IS_OK(nt_status)) {
702                 talloc_free(tmp_ctx);
703                 return nt_status;
704         }
705
706         talloc_steal(mem_ctx, *user_info_dc);
707         talloc_free(tmp_ctx);
708
709         return NT_STATUS_OK;
710 }
711
712 static NTSTATUS authsam_ignoredomain_want_check(struct auth_method_context *ctx,
713                                                 TALLOC_CTX *mem_ctx,
714                                                 const struct auth_usersupplied_info *user_info)
715 {
716         if (!user_info->mapped.account_name || !*user_info->mapped.account_name) {
717                 return NT_STATUS_NOT_IMPLEMENTED;
718         }
719
720         return NT_STATUS_OK;
721 }
722
723 /****************************************************************************
724 Check SAM security (above) but with a few extra checks.
725 ****************************************************************************/
726 static NTSTATUS authsam_want_check(struct auth_method_context *ctx,
727                                    TALLOC_CTX *mem_ctx,
728                                    const struct auth_usersupplied_info *user_info)
729 {
730         const char *effective_domain = user_info->mapped.domain_name;
731         bool is_local_name = false;
732         bool is_my_domain = false;
733         const char *p = NULL;
734         struct dsdb_trust_routing_table *trt = NULL;
735         const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
736         NTSTATUS status;
737
738         if (!user_info->mapped.account_name || !*user_info->mapped.account_name) {
739                 return NT_STATUS_NOT_IMPLEMENTED;
740         }
741
742         if (effective_domain == NULL) {
743                 effective_domain = "";
744         }
745
746         is_local_name = lpcfg_is_myname(ctx->auth_ctx->lp_ctx,
747                                         effective_domain);
748
749         /* check whether or not we service this domain/workgroup name */
750         switch (lpcfg_server_role(ctx->auth_ctx->lp_ctx)) {
751         case ROLE_STANDALONE:
752                 return NT_STATUS_OK;
753
754         case ROLE_DOMAIN_MEMBER:
755                 if (is_local_name) {
756                         return NT_STATUS_OK;
757                 }
758
759                 DBG_DEBUG("%s is not one of my local names (DOMAIN_MEMBER)\n",
760                           effective_domain);
761                 return NT_STATUS_NOT_IMPLEMENTED;
762
763         case ROLE_ACTIVE_DIRECTORY_DC:
764                 /* handled later */
765                 break;
766
767         default:
768                 DBG_ERR("lpcfg_server_role() has an undefined value\n");
769                 return NT_STATUS_INVALID_SERVER_STATE;
770         }
771
772         /*
773          * Now we handle the AD DC case...
774          */
775
776         is_my_domain = lpcfg_is_my_domain_or_realm(ctx->auth_ctx->lp_ctx,
777                                                    effective_domain);
778         if (is_my_domain) {
779                 return NT_STATUS_OK;
780         }
781
782         if (user_info->mapped_state) {
783                 /*
784                  * The caller already did a cracknames call.
785                  */
786                 DBG_DEBUG("%s is not one domain name (DC)\n",
787                           effective_domain);
788                 return NT_STATUS_NOT_IMPLEMENTED;
789         }
790
791         if (!strequal(effective_domain, "")) {
792                 DBG_DEBUG("%s is not one domain name (DC)\n",
793                           effective_domain);
794                 return NT_STATUS_NOT_IMPLEMENTED;
795         }
796
797         p = strchr_m(user_info->mapped.account_name, '@');
798         if (p == NULL) {
799                 /*
800                  * An empty to domain name should be handled
801                  * as the local domain name.
802                  */
803                 return NT_STATUS_OK;
804         }
805
806         effective_domain = p + 1;
807         is_my_domain = lpcfg_is_my_domain_or_realm(ctx->auth_ctx->lp_ctx,
808                                                    effective_domain);
809         if (is_my_domain) {
810                 return NT_STATUS_OK;
811         }
812
813         if (strequal(effective_domain, "")) {
814                 DBG_DEBUG("authsam_check_password: upn without realm (DC)\n");
815                 return NT_STATUS_NOT_IMPLEMENTED;
816         }
817
818         /*
819          * as last option we check the routing table if the
820          * domain is within our forest.
821          */
822         status = dsdb_trust_routing_table_load(ctx->auth_ctx->sam_ctx,
823                                                mem_ctx, &trt);
824         if (!NT_STATUS_IS_OK(status)) {
825                 DBG_ERR("authsam_check_password: dsdb_trust_routing_table_load() %s\n",
826                          nt_errstr(status));
827                 return status;
828         }
829
830         tdo = dsdb_trust_routing_by_name(trt, effective_domain);
831         if (tdo == NULL) {
832                 DBG_DEBUG("%s is not a known TLN (DC)\n",
833                           effective_domain);
834                 TALLOC_FREE(trt);
835                 return NT_STATUS_NOT_IMPLEMENTED;
836         }
837
838         if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST)) {
839                 DBG_DEBUG("%s is not a TLN in our forest (DC)\n",
840                           effective_domain);
841                 TALLOC_FREE(trt);
842                 return NT_STATUS_NOT_IMPLEMENTED;
843         }
844
845         /*
846          * This principal is within our forest.
847          * we'll later do a crack_name_to_nt4_name()
848          * to check if it's in our domain.
849          */
850         TALLOC_FREE(trt);
851         return NT_STATUS_OK;
852 }
853
854 /* Wrapper for the auth subsystem pointer */
855 static NTSTATUS authsam_get_user_info_dc_principal_wrapper(TALLOC_CTX *mem_ctx,
856                                                           struct auth4_context *auth_context,
857                                                           const char *principal,
858                                                           struct ldb_dn *user_dn,
859                                                           struct auth_user_info_dc **user_info_dc)
860 {
861         return authsam_get_user_info_dc_principal(mem_ctx, auth_context->lp_ctx, auth_context->sam_ctx,
862                                                  principal, user_dn, user_info_dc);
863 }
864 static const struct auth_operations sam_ignoredomain_ops = {
865         .name                      = "sam_ignoredomain",
866         .want_check                = authsam_ignoredomain_want_check,
867         .check_password            = authsam_check_password_internals,
868         .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper,
869 };
870
871 static const struct auth_operations sam_ops = {
872         .name                      = "sam",
873         .want_check                = authsam_want_check,
874         .check_password            = authsam_check_password_internals,
875         .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper,
876 };
877
878 _PUBLIC_ NTSTATUS auth4_sam_init(TALLOC_CTX *);
879 _PUBLIC_ NTSTATUS auth4_sam_init(TALLOC_CTX *ctx)
880 {
881         NTSTATUS ret;
882
883         ret = auth_register(ctx, &sam_ops);
884         if (!NT_STATUS_IS_OK(ret)) {
885                 DEBUG(0,("Failed to register 'sam' auth backend!\n"));
886                 return ret;
887         }
888
889         ret = auth_register(ctx, &sam_ignoredomain_ops);
890         if (!NT_STATUS_IS_OK(ret)) {
891                 DEBUG(0,("Failed to register 'sam_ignoredomain' auth backend!\n"));
892                 return ret;
893         }
894
895         return ret;
896 }