r14464: Don't include ndr_BASENAME.h files unless strictly required, instead
[kai/samba-autobuild/.git] / source4 / auth / auth_sam.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Password and authentication handling
4    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2004
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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "system/time.h"
25 #include "auth/auth.h"
26 #include "db_wrap.h"
27 #include "dsdb/samdb/samdb.h"
28 #include "libcli/security/proto.h"
29 #include "libcli/ldap/ldap.h"
30 #include "librpc/gen_ndr/ndr_security.h"
31
32 static const char *user_attrs[] = {
33         /* requried for the krb5 kdc*/
34         "objectClass",
35         "sAMAccountName",
36         "userPrincipalName",
37         "servicePrincipalName",
38         "msDS-KeyVersionNumber",
39         "krb5Key",
40
41         /* passwords */
42         "lmPwdHash", 
43         "ntPwdHash",
44
45         "userAccountControl",
46
47         "pwdLastSet",
48         "accountExpires",
49         
50         "objectSid",
51
52         /* check 'allowed workstations' */
53         "userWorkstations",
54                        
55         /* required for server_info, not access control: */
56         "displayName",
57         "scriptPath",
58         "profilePath",
59         "homeDirectory",
60         "homeDrive",
61         "lastLogon",
62         "lastLogoff",
63         "accountExpires",
64         "badPwdCount",
65         "logonCount",
66         "primaryGroupID",
67         NULL,
68 };
69
70 static const char *domain_ref_attrs[] =  {"nETBIOSName", "nCName", 
71                                           "dnsRoot", "objectClass", NULL};
72
73 /****************************************************************************
74  Do a specific test for an smb password being correct, given a smb_password and
75  the lanman and NT responses.
76 ****************************************************************************/
77 static NTSTATUS authsam_password_ok(struct auth_context *auth_context,
78                                     TALLOC_CTX *mem_ctx,
79                                     uint16_t acct_flags,
80                                     const struct samr_Password *lm_pwd, 
81                                     const struct samr_Password *nt_pwd,
82                                     const struct auth_usersupplied_info *user_info, 
83                                     DATA_BLOB *user_sess_key, 
84                                     DATA_BLOB *lm_sess_key)
85 {
86         NTSTATUS status;
87
88         if (acct_flags & ACB_PWNOTREQ) {
89                 if (lp_null_passwords()) {
90                         DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", 
91                                  user_info->mapped.account_name));
92                         return NT_STATUS_OK;
93                 } else {
94                         DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", 
95                                  user_info->mapped.account_name));
96                         return NT_STATUS_LOGON_FAILURE;
97                 }               
98         }
99
100         switch (user_info->password_state) {
101         case AUTH_PASSWORD_PLAIN: 
102         {
103                 const struct auth_usersupplied_info *user_info_temp;    
104                 status = encrypt_user_info(mem_ctx, auth_context, 
105                                            AUTH_PASSWORD_HASH, 
106                                            user_info, &user_info_temp);
107                 if (!NT_STATUS_IS_OK(status)) {
108                         DEBUG(1, ("Failed to convert plaintext password to password HASH: %s\n", nt_errstr(status)));
109                         return status;
110                 }
111                 user_info = user_info_temp;
112
113                 /* NO break */
114         }
115         case AUTH_PASSWORD_HASH:
116                 *lm_sess_key = data_blob(NULL, 0);
117                 *user_sess_key = data_blob(NULL, 0);
118                 status = hash_password_check(mem_ctx, 
119                                              user_info->password.hash.lanman,
120                                              user_info->password.hash.nt,
121                                              user_info->mapped.account_name,
122                                              lm_pwd, nt_pwd);
123                 NT_STATUS_NOT_OK_RETURN(status);
124                 break;
125                 
126         case AUTH_PASSWORD_RESPONSE:
127                 status = ntlm_password_check(mem_ctx, user_info->logon_parameters, 
128                                              &auth_context->challenge.data, 
129                                              &user_info->password.response.lanman, 
130                                              &user_info->password.response.nt,
131                                              user_info->mapped.account_name,
132                                              user_info->client.account_name, 
133                                              user_info->client.domain_name, 
134                                              lm_pwd, nt_pwd,
135                                              user_sess_key, lm_sess_key);
136                 NT_STATUS_NOT_OK_RETURN(status);
137                 break;
138         }
139
140         if (user_sess_key && user_sess_key->data) {
141                 talloc_steal(auth_context, user_sess_key->data);
142         }
143         if (lm_sess_key && lm_sess_key->data) {
144                 talloc_steal(auth_context, lm_sess_key->data);
145         }
146
147         return NT_STATUS_OK;
148 }
149
150
151 /****************************************************************************
152  Do a specific test for a SAM_ACCOUNT being vaild for this connection 
153  (ie not disabled, expired and the like).
154 ****************************************************************************/
155 NTSTATUS authsam_account_ok(TALLOC_CTX *mem_ctx,
156                             struct ldb_context *sam_ctx,
157                             uint32_t logon_parameters,
158                             struct ldb_message *msg,
159                             struct ldb_message *msg_domain_ref,
160                             const char *logon_workstation,
161                             const char *name_for_logs)
162 {
163         uint16_t acct_flags;
164         const char *workstation_list;
165         NTTIME acct_expiry;
166         NTTIME must_change_time;
167         NTTIME last_set_time;
168
169         struct ldb_dn *domain_dn = samdb_result_dn(mem_ctx, msg_domain_ref, "nCName", ldb_dn_new(mem_ctx));
170
171         NTTIME now;
172         DEBUG(4,("authsam_account_ok: Checking SMB password for user %s\n", name_for_logs));
173
174         acct_flags = samdb_result_acct_flags(msg, "userAccountControl");
175         
176         acct_expiry = samdb_result_nttime(msg, "accountExpires", 0);
177         must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx, 
178                                                               domain_dn, msg);
179         last_set_time = samdb_result_nttime(msg, "pwdLastSet", 0);
180
181         workstation_list = samdb_result_string(msg, "userWorkstations", NULL);
182
183         /* Quit if the account was disabled. */
184         if (acct_flags & ACB_DISABLED) {
185                 DEBUG(1,("authsam_account_ok: Account for user '%s' was disabled.\n", name_for_logs));
186                 return NT_STATUS_ACCOUNT_DISABLED;
187         }
188
189         /* Quit if the account was locked out. */
190         if (acct_flags & ACB_AUTOLOCK) {
191                 DEBUG(1,("authsam_account_ok: Account for user %s was locked out.\n", name_for_logs));
192                 return NT_STATUS_ACCOUNT_LOCKED_OUT;
193         }
194
195         /* Test account expire time */
196         unix_to_nt_time(&now, time(NULL));
197         if (now > acct_expiry) {
198                 DEBUG(1,("authsam_account_ok: Account for user '%s' has expired.\n", name_for_logs));
199                 DEBUG(3,("authsam_account_ok: Account expired at '%s'.\n", 
200                          nt_time_string(mem_ctx, acct_expiry)));
201                 return NT_STATUS_ACCOUNT_EXPIRED;
202         }
203
204         if (!(acct_flags & ACB_PWNOEXP)) {
205                 /* check for immediate expiry "must change at next logon" */
206                 if (must_change_time == 0 && last_set_time != 0) {
207                         DEBUG(1,("sam_account_ok: Account for user '%s' password must change!.\n", 
208                                  name_for_logs));
209                         return NT_STATUS_PASSWORD_MUST_CHANGE;
210                 }
211
212                 /* check for expired password */
213                 if ((must_change_time != 0) && (must_change_time < now)) {
214                         DEBUG(1,("sam_account_ok: Account for user '%s' password expired!.\n", 
215                                  name_for_logs));
216                         DEBUG(1,("sam_account_ok: Password expired at '%s' unix time.\n", 
217                                  nt_time_string(mem_ctx, must_change_time)));
218                         return NT_STATUS_PASSWORD_EXPIRED;
219                 }
220         }
221
222         /* Test workstation. Workstation list is comma separated. */
223         if (logon_workstation && workstation_list && *workstation_list) {
224                 BOOL invalid_ws = True;
225                 int i;
226                 const char **workstations = str_list_make(mem_ctx, workstation_list, ",");
227                 
228                 for (i = 0; workstations && workstations[i]; i++) {
229                         DEBUG(10,("sam_account_ok: checking for workstation match '%s' and '%s'\n",
230                                   workstations[i], logon_workstation));
231
232                         if (strequal(workstations[i], logon_workstation)) {
233                                 invalid_ws = False;
234                                 break;
235                         }
236                 }
237
238                 talloc_free(workstations);
239
240                 if (invalid_ws) {
241                         return NT_STATUS_INVALID_WORKSTATION;
242                 }
243         }
244         
245         if (acct_flags & ACB_DOMTRUST) {
246                 DEBUG(2,("sam_account_ok: Domain trust account %s denied by server\n", name_for_logs));
247                 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
248         }
249         
250         if (!(logon_parameters & MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT)) {
251                 if (acct_flags & ACB_SVRTRUST) {
252                         DEBUG(2,("sam_account_ok: Server trust account %s denied by server\n", name_for_logs));
253                         return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
254                 }
255         }
256         if (!(logon_parameters & MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT)) {
257                 if (acct_flags & ACB_WSTRUST) {
258                         DEBUG(4,("sam_account_ok: Wksta trust account %s denied by server\n", name_for_logs));
259                         return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
260                 }
261         }
262
263         return NT_STATUS_OK;
264 }
265
266 /****************************************************************************
267  Look for the specified user in the sam, return ldb result structures
268 ****************************************************************************/
269
270 static NTSTATUS authsam_search_account(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx,
271                                        const char *account_name,
272                                        const char *domain_name,
273                                        struct ldb_message ***ret_msgs,
274                                        struct ldb_message ***ret_msgs_domain_ref)
275 {
276         struct ldb_message **msgs_tmp;
277         struct ldb_message **msgs;
278         struct ldb_message **msgs_domain_ref;
279
280         int ret;
281         int ret_domain;
282
283         const struct ldb_dn *domain_dn = NULL;
284
285         if (domain_name) {
286                 char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
287                 /* find the domain's DN */
288                 ret_domain = gendb_search(sam_ctx, mem_ctx, NULL, &msgs_domain_ref, domain_ref_attrs,
289                                           "(&(&(|(&(dnsRoot=%s)(nETBIOSName=*))(nETBIOSName=%s))(objectclass=crossRef))(ncName=*))", 
290                                           escaped_domain, escaped_domain);
291                 if (ret_domain == -1) {
292                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
293                 }
294
295                 if (ret_domain == 0) {
296                         DEBUG(3,("sam_search_user: Couldn't find domain [%s] in samdb.\n", 
297                                  domain_name));
298                         return NT_STATUS_NO_SUCH_USER;
299                 }
300
301                 if (ret_domain > 1) {
302                         DEBUG(0,("Found %d records matching domain [%s]\n", 
303                                  ret_domain, domain_name));
304                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
305                 }
306
307                 domain_dn = samdb_result_dn(mem_ctx, msgs_domain_ref[0], "nCName", NULL);
308         }
309
310         /* pull the user attributes */
311         ret = gendb_search(sam_ctx, mem_ctx, domain_dn, &msgs, user_attrs,
312                            "(&(sAMAccountName=%s)(objectclass=user))", 
313                            ldb_binary_encode_string(mem_ctx, account_name));
314         if (ret == -1) {
315                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
316         }
317
318         if (ret == 0) {
319                 DEBUG(3,("sam_search_user: Couldn't find user [%s] in samdb.\n", 
320                          account_name));
321                 return NT_STATUS_NO_SUCH_USER;
322         }
323
324         if (ret > 1) {
325                 DEBUG(0,("Found %d records matching user [%s]\n", ret, account_name));
326                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
327         }
328
329         if (!domain_name) {
330                 struct dom_sid *domain_sid;
331
332                 domain_sid = samdb_result_sid_prefix(mem_ctx, msgs[0], "objectSid");
333                 if (!domain_sid) {
334                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
335                 }
336
337                 /* find the domain's DN */
338                 ret = gendb_search(sam_ctx, mem_ctx, NULL, &msgs_tmp, NULL,
339                                    "(&(objectSid=%s)(objectclass=domain))", 
340                                    ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
341                 if (ret == -1) {
342                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
343                 }
344                 
345                 if (ret == 0) {
346                         DEBUG(3,("check_sam_security: Couldn't find domain_sid [%s] in passdb file.\n",
347                                  dom_sid_string(mem_ctx, domain_sid)));
348                         return NT_STATUS_NO_SUCH_USER;
349                 }
350                 
351                 if (ret > 1) {
352                         DEBUG(0,("Found %d records matching domain_sid [%s]\n", 
353                                  ret, dom_sid_string(mem_ctx, domain_sid)));
354                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
355                 }
356
357                 ret_domain = gendb_search(sam_ctx, mem_ctx, NULL, &msgs_domain_ref, domain_ref_attrs,
358                                           "(nCName=%s)", ldb_dn_linearize(msgs_tmp, msgs_tmp[0]->dn));
359
360                 if (ret_domain == -1) {
361                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
362                 }
363                 
364                 if (ret_domain == 0) {
365                         DEBUG(3,("check_sam_security: Couldn't find domain [%s] in passdb file.\n",
366                                  ldb_dn_linearize(msgs_tmp, msgs_tmp[0]->dn)));
367                         return NT_STATUS_NO_SUCH_USER;
368                 }
369                 
370                 if (ret_domain > 1) {
371                         DEBUG(0,("Found %d records matching domain [%s]\n", 
372                                  ret_domain, ldb_dn_linearize(msgs_tmp, msgs_tmp[0]->dn)));
373                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
374                 }
375
376         }
377
378         *ret_msgs = msgs;
379         *ret_msgs_domain_ref = msgs_domain_ref;
380         
381         return NT_STATUS_OK;
382 }
383
384 static NTSTATUS authsam_authenticate(struct auth_context *auth_context, 
385                                      TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx, 
386                                      struct ldb_message **msgs,
387                                      struct ldb_message **msgs_domain_ref,
388                                      const struct auth_usersupplied_info *user_info, 
389                                      DATA_BLOB *user_sess_key, DATA_BLOB *lm_sess_key) 
390 {
391         struct samr_Password *lm_pwd, *nt_pwd;
392         NTSTATUS nt_status;
393         uint16_t acct_flags = samdb_result_acct_flags(msgs[0], "userAccountControl");
394         
395         /* Quit if the account was locked out. */
396         if (acct_flags & ACB_AUTOLOCK) {
397                 DEBUG(3,("check_sam_security: Account for user %s was locked out.\n", 
398                          user_info->mapped.account_name));
399                 return NT_STATUS_ACCOUNT_LOCKED_OUT;
400         }
401
402         /* You can only do an interactive login to normal accounts */
403         if (user_info->flags & USER_INFO_INTERACTIVE_LOGON) {
404                 if (!(acct_flags & ACB_NORMAL)) {
405                         return NT_STATUS_NO_SUCH_USER;
406                 }
407         }
408
409         nt_status = samdb_result_passwords(mem_ctx, msgs[0], &lm_pwd, &nt_pwd);
410         NT_STATUS_NOT_OK_RETURN(nt_status);
411
412         nt_status = authsam_password_ok(auth_context, mem_ctx, 
413                                         acct_flags, lm_pwd, nt_pwd,
414                                         user_info, user_sess_key, lm_sess_key);
415         NT_STATUS_NOT_OK_RETURN(nt_status);
416
417         nt_status = authsam_account_ok(mem_ctx, sam_ctx, 
418                                        user_info->logon_parameters,
419                                        msgs[0],
420                                        msgs_domain_ref[0],
421                                        user_info->workstation_name,
422                                        user_info->mapped.account_name);
423
424         return nt_status;
425 }
426
427 NTSTATUS authsam_make_server_info(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx,
428                                   struct ldb_message *msg,
429                                   struct ldb_message *msg_domain_ref,
430                                   DATA_BLOB user_sess_key, DATA_BLOB lm_sess_key,
431                                   struct auth_serversupplied_info **_server_info)
432 {
433         struct auth_serversupplied_info *server_info;
434         struct ldb_message **group_msgs;
435         int group_ret;
436         const char *group_attrs[3] = { "sAMAccountType", "objectSid", NULL }; 
437         /* find list of sids */
438         struct dom_sid **groupSIDs = NULL;
439         struct dom_sid *account_sid;
440         struct dom_sid *primary_group_sid;
441         const char *str;
442         struct ldb_dn *ncname;
443         int i;
444         uint_t rid;
445         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
446
447         group_ret = gendb_search(sam_ctx,
448                                  tmp_ctx, NULL, &group_msgs, group_attrs,
449                                  "(&(member=%s)(sAMAccountType=*))", 
450                                  ldb_dn_linearize(tmp_ctx, msg->dn));
451         if (group_ret == -1) {
452                 talloc_free(tmp_ctx);
453                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
454         }
455
456         server_info = talloc(mem_ctx, struct auth_serversupplied_info);
457         NT_STATUS_HAVE_NO_MEMORY(server_info);
458         
459         if (group_ret > 0) {
460                 groupSIDs = talloc_array(server_info, struct dom_sid *, group_ret);
461                 NT_STATUS_HAVE_NO_MEMORY(groupSIDs);
462         }
463
464         /* Need to unroll some nested groups, but not aliases */
465         for (i = 0; i < group_ret; i++) {
466                 groupSIDs[i] = samdb_result_dom_sid(groupSIDs, 
467                                                     group_msgs[i], "objectSid");
468                 NT_STATUS_HAVE_NO_MEMORY(groupSIDs[i]);
469         }
470
471         talloc_free(tmp_ctx);
472
473         account_sid = samdb_result_dom_sid(server_info, msg, "objectSid");
474         NT_STATUS_HAVE_NO_MEMORY(account_sid);
475
476         primary_group_sid = dom_sid_dup(server_info, account_sid);
477         NT_STATUS_HAVE_NO_MEMORY(primary_group_sid);
478
479         rid = samdb_result_uint(msg, "primaryGroupID", ~0);
480         if (rid == ~0) {
481                 if (group_ret > 0) {
482                         primary_group_sid = groupSIDs[0];
483                 } else {
484                         primary_group_sid = NULL;
485                 }
486         } else {
487                 primary_group_sid->sub_auths[primary_group_sid->num_auths-1] = rid;
488         }
489
490         server_info->account_sid = account_sid;
491         server_info->primary_group_sid = primary_group_sid;
492         
493         server_info->n_domain_groups = group_ret;
494         server_info->domain_groups = groupSIDs;
495
496         server_info->account_name = talloc_steal(server_info, samdb_result_string(msg, "sAMAccountName", NULL));
497
498         server_info->domain_name = talloc_steal(server_info, samdb_result_string(msg_domain_ref, "nETBIOSName", NULL));
499
500         str = samdb_result_string(msg, "displayName", "");
501         server_info->full_name = talloc_strdup(server_info, str);
502         NT_STATUS_HAVE_NO_MEMORY(server_info->full_name);
503
504         str = samdb_result_string(msg, "scriptPath", "");
505         server_info->logon_script = talloc_strdup(server_info, str);
506         NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script);
507
508         str = samdb_result_string(msg, "profilePath", "");
509         server_info->profile_path = talloc_strdup(server_info, str);
510         NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path);
511
512         str = samdb_result_string(msg, "homeDirectory", "");
513         server_info->home_directory = talloc_strdup(server_info, str);
514         NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory);
515
516         str = samdb_result_string(msg, "homeDrive", "");
517         server_info->home_drive = talloc_strdup(server_info, str);
518         NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive);
519
520         server_info->logon_server = talloc_strdup(server_info, lp_netbios_name());
521         NT_STATUS_HAVE_NO_MEMORY(server_info->logon_server);
522
523         server_info->last_logon = samdb_result_nttime(msg, "lastLogon", 0);
524         server_info->last_logoff = samdb_result_nttime(msg, "lastLogoff", 0);
525         server_info->acct_expiry = samdb_result_nttime(msg, "accountExpires", 0);
526         server_info->last_password_change = samdb_result_nttime(msg, "pwdLastSet", 0);
527
528         ncname = samdb_result_dn(mem_ctx, msg_domain_ref, "nCName", NULL);
529         if (!ncname) {
530                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
531         }
532         server_info->allow_password_change
533                 = samdb_result_allow_password_change(sam_ctx, mem_ctx, 
534                                                      ncname, msg, "pwdLastSet");
535         server_info->force_password_change
536                 = samdb_result_force_password_change(sam_ctx, mem_ctx, 
537                                                      ncname, msg);
538         
539         server_info->logon_count = samdb_result_uint(msg, "logonCount", 0);
540         server_info->bad_password_count = samdb_result_uint(msg, "badPwdCount", 0);
541
542         server_info->acct_flags = samdb_result_acct_flags(msg, "userAccountControl");
543
544         server_info->user_session_key = user_sess_key;
545         server_info->lm_session_key = lm_sess_key;
546
547         server_info->authenticated = True;
548
549         *_server_info = server_info;
550
551         return NT_STATUS_OK;
552 }
553
554 NTSTATUS sam_get_results_principal(struct ldb_context *sam_ctx,
555                                    TALLOC_CTX *mem_ctx, const char *principal,
556                                    struct ldb_message ***msgs,
557                                    struct ldb_message ***msgs_domain_ref)
558 {                          
559         struct ldb_dn *user_dn, *domain_dn;
560         NTSTATUS nt_status;
561         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
562         int ret;
563
564         if (!tmp_ctx) {
565                 return NT_STATUS_NO_MEMORY;
566         }
567
568         nt_status = crack_user_principal_name(sam_ctx, tmp_ctx, principal, &user_dn, &domain_dn);
569         if (!NT_STATUS_IS_OK(nt_status)) {
570                 talloc_free(tmp_ctx);
571                 return nt_status;
572         }
573         
574         /* grab domain info from the reference */
575         ret = gendb_search(sam_ctx, tmp_ctx, NULL, msgs_domain_ref, domain_ref_attrs,
576                            "(ncName=%s)", ldb_dn_linearize(tmp_ctx, domain_dn));
577
578         if (ret != 1) {
579                 talloc_free(tmp_ctx);
580                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
581         }
582         
583         /* pull the user attributes */
584         ret = gendb_search_dn(sam_ctx, tmp_ctx, 
585                               user_dn, msgs, user_attrs);
586         if (ret != 1) {
587                 talloc_free(tmp_ctx);
588                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
589         }
590         talloc_steal(mem_ctx, *msgs);
591         talloc_steal(mem_ctx, *msgs_domain_ref);
592         talloc_free(tmp_ctx);
593         
594         return NT_STATUS_OK;
595 }
596                                    
597 /* Used in the gensec_gssapi and gensec_krb5 server-side code, where the PAC isn't available */
598 NTSTATUS sam_get_server_info_principal(TALLOC_CTX *mem_ctx, const char *principal,
599                                        struct auth_serversupplied_info **server_info)
600 {
601         NTSTATUS nt_status;
602         DATA_BLOB user_sess_key = data_blob(NULL, 0);
603         DATA_BLOB lm_sess_key = data_blob(NULL, 0);
604
605         struct ldb_message **msgs;
606         struct ldb_message **msgs_domain_ref;
607         struct ldb_context *sam_ctx;
608
609         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
610         if (!tmp_ctx) {
611                 return NT_STATUS_NO_MEMORY;
612         }
613
614         sam_ctx = samdb_connect(tmp_ctx, system_session(tmp_ctx));
615         if (sam_ctx == NULL) {
616                 talloc_free(tmp_ctx);
617                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
618         }
619
620         nt_status = sam_get_results_principal(sam_ctx, tmp_ctx, principal, 
621                                               &msgs, &msgs_domain_ref);
622         if (!NT_STATUS_IS_OK(nt_status)) {
623                 return nt_status;
624         }
625
626         nt_status = authsam_make_server_info(tmp_ctx, sam_ctx, msgs[0], msgs_domain_ref[0],
627                                              user_sess_key, lm_sess_key,
628                                              server_info);
629         if (NT_STATUS_IS_OK(nt_status)) {
630                 talloc_steal(mem_ctx, *server_info);
631         }
632         talloc_free(tmp_ctx);
633         return nt_status;
634 }
635
636 static NTSTATUS authsam_check_password_internals(struct auth_method_context *ctx,
637                                                  TALLOC_CTX *mem_ctx,
638                                                  const char *domain,
639                                                  const struct auth_usersupplied_info *user_info, 
640                                                  struct auth_serversupplied_info **server_info)
641 {
642         NTSTATUS nt_status;
643         const char *account_name = user_info->mapped.account_name;
644         struct ldb_message **msgs;
645         struct ldb_message **domain_ref_msgs;
646         struct ldb_context *sam_ctx;
647         DATA_BLOB user_sess_key, lm_sess_key;
648         TALLOC_CTX *tmp_ctx;
649
650         if (!account_name || !*account_name) {
651                 /* 'not for me' */
652                 return NT_STATUS_NOT_IMPLEMENTED;
653         }
654
655         tmp_ctx = talloc_new(mem_ctx);
656         if (!tmp_ctx) {
657                 return NT_STATUS_NO_MEMORY;
658         }
659
660         sam_ctx = samdb_connect(tmp_ctx, system_session(mem_ctx));
661         if (sam_ctx == NULL) {
662                 talloc_free(tmp_ctx);
663                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
664         }
665
666         nt_status = authsam_search_account(tmp_ctx, sam_ctx, account_name, domain, &msgs, &domain_ref_msgs);
667         if (!NT_STATUS_IS_OK(nt_status)) {
668                 talloc_free(tmp_ctx);
669                 return nt_status;
670         }
671
672         nt_status = authsam_authenticate(ctx->auth_ctx, tmp_ctx, sam_ctx, msgs, domain_ref_msgs, user_info,
673                                          &user_sess_key, &lm_sess_key);
674         if (!NT_STATUS_IS_OK(nt_status)) {
675                 talloc_free(tmp_ctx);
676                 return nt_status;
677         }
678
679         nt_status = authsam_make_server_info(tmp_ctx, sam_ctx, msgs[0], domain_ref_msgs[0],
680                                              user_sess_key, lm_sess_key,
681                                              server_info);
682         if (!NT_STATUS_IS_OK(nt_status)) {
683                 talloc_free(tmp_ctx);
684                 return nt_status;
685         }
686
687         talloc_steal(mem_ctx, *server_info);
688         talloc_free(tmp_ctx);
689
690         return NT_STATUS_OK;
691 }
692
693 static NTSTATUS authsam_ignoredomain_check_password(struct auth_method_context *ctx,
694                                                     TALLOC_CTX *mem_ctx,
695                                                     const struct auth_usersupplied_info *user_info, 
696                                                     struct auth_serversupplied_info **server_info)
697 {
698         return authsam_check_password_internals(ctx, mem_ctx, NULL, user_info, server_info);
699 }
700
701 /****************************************************************************
702 Check SAM security (above) but with a few extra checks.
703 ****************************************************************************/
704 static NTSTATUS authsam_check_password(struct auth_method_context *ctx,
705                                        TALLOC_CTX *mem_ctx,
706                                        const struct auth_usersupplied_info *user_info, 
707                                        struct auth_serversupplied_info **server_info)
708 {
709         const char *domain;
710         BOOL is_local_name, is_my_domain;
711
712         is_local_name = is_myname(user_info->mapped.domain_name);
713         is_my_domain  = strequal(user_info->mapped.domain_name, lp_workgroup());
714
715         /* check whether or not we service this domain/workgroup name */
716         switch (lp_server_role()) {
717                 case ROLE_STANDALONE:
718                         domain = lp_netbios_name();
719                         break;
720                 case ROLE_DOMAIN_MEMBER:
721                         if (!is_local_name) {
722                                 DEBUG(6,("authsam_check_password: %s is not one of my local names (%s)\n",
723                                         user_info->mapped.domain_name, (lp_server_role() == ROLE_DOMAIN_MEMBER 
724                                         ? "ROLE_DOMAIN_MEMBER" : "ROLE_STANDALONE") ));
725                                 return NT_STATUS_NOT_IMPLEMENTED;
726                         }
727                         domain = lp_netbios_name();
728                         break;
729                 case ROLE_DOMAIN_PDC:
730                 case ROLE_DOMAIN_BDC:
731                         if (!is_local_name && !is_my_domain) {
732                                 DEBUG(6,("authsam_check_password: %s is not one of my local names or domain name (DC)\n",
733                                         user_info->mapped.domain_name));
734                                 return NT_STATUS_NOT_IMPLEMENTED;
735                         }
736                         domain = lp_workgroup();
737                         break;
738                 default:
739                         DEBUG(6,("authsam_check_password: lp_server_role() has an undefined value\n"));
740                         return NT_STATUS_NOT_IMPLEMENTED;
741         }
742
743         return authsam_check_password_internals(ctx, mem_ctx, domain, user_info, server_info);
744 }
745
746 static const struct auth_operations sam_ignoredomain_ops = {
747         .name           = "sam_ignoredomain",
748         .get_challenge  = auth_get_challenge_not_implemented,
749         .check_password = authsam_ignoredomain_check_password
750 };
751
752 static const struct auth_operations sam_ops = {
753         .name           = "sam",
754         .get_challenge  = auth_get_challenge_not_implemented,
755         .check_password = authsam_check_password
756 };
757
758 NTSTATUS auth_sam_init(void)
759 {
760         NTSTATUS ret;
761
762         ret = auth_register(&sam_ops);
763         if (!NT_STATUS_IS_OK(ret)) {
764                 DEBUG(0,("Failed to register 'sam' auth backend!\n"));
765                 return ret;
766         }
767
768         ret = auth_register(&sam_ignoredomain_ops);
769         if (!NT_STATUS_IS_OK(ret)) {
770                 DEBUG(0,("Failed to register 'sam_ignoredomain' auth backend!\n"));
771                 return ret;
772         }
773
774         return ret;
775 }