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