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