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