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
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.
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.
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.
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"
30 /****************************************************************************
31 Do a specific test for an smb password being correct, given a smb_password and
32 the lanman and NT responses.
33 ****************************************************************************/
34 static NTSTATUS
authsam_password_ok(struct auth_context
*auth_context
,
37 const struct samr_Password
*lm_pwd
,
38 const struct samr_Password
*nt_pwd
,
39 const struct auth_usersupplied_info
*user_info
,
40 DATA_BLOB
*user_sess_key
,
41 DATA_BLOB
*lm_sess_key
)
45 if (acct_flags
& ACB_PWNOTREQ
) {
46 if (lp_null_passwords()) {
47 DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n",
48 user_info
->mapped
.account_name
));
51 DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n",
52 user_info
->mapped
.account_name
));
53 return NT_STATUS_LOGON_FAILURE
;
57 switch (user_info
->password_state
) {
58 case AUTH_PASSWORD_PLAIN
:
60 const struct auth_usersupplied_info
*user_info_temp
;
61 status
= encrypt_user_info(mem_ctx
, auth_context
,
63 user_info
, &user_info_temp
);
64 if (!NT_STATUS_IS_OK(status
)) {
65 DEBUG(1, ("Failed to convert plaintext password to password HASH: %s\n", nt_errstr(status
)));
68 user_info
= user_info_temp
;
72 case AUTH_PASSWORD_HASH
:
73 *lm_sess_key
= data_blob(NULL
, 0);
74 *user_sess_key
= data_blob(NULL
, 0);
75 status
= hash_password_check(mem_ctx
,
76 user_info
->password
.hash
.lanman
,
77 user_info
->password
.hash
.nt
,
78 user_info
->mapped
.account_name
,
80 NT_STATUS_NOT_OK_RETURN(status
);
83 case AUTH_PASSWORD_RESPONSE
:
84 status
= ntlm_password_check(mem_ctx
, &auth_context
->challenge
.data
,
85 &user_info
->password
.response
.lanman
,
86 &user_info
->password
.response
.nt
,
87 user_info
->mapped
.account_name
,
88 user_info
->client
.account_name
,
89 user_info
->client
.domain_name
,
91 user_sess_key
, lm_sess_key
);
92 NT_STATUS_NOT_OK_RETURN(status
);
96 if (user_sess_key
&& user_sess_key
->data
) {
97 talloc_steal(auth_context
, user_sess_key
->data
);
99 if (lm_sess_key
&& lm_sess_key
->data
) {
100 talloc_steal(auth_context
, lm_sess_key
->data
);
107 /****************************************************************************
108 Do a specific test for a SAM_ACCOUNT being vaild for this connection
109 (ie not disabled, expired and the like).
110 ****************************************************************************/
111 static NTSTATUS
authsam_account_ok(TALLOC_CTX
*mem_ctx
,
114 NTTIME must_change_time
,
115 NTTIME last_set_time
,
116 const char *workstation_list
,
117 const struct auth_usersupplied_info
*user_info
)
120 DEBUG(4,("authsam_account_ok: Checking SMB password for user %s\n", user_info
->mapped
.account_name
));
122 /* Quit if the account was disabled. */
123 if (acct_flags
& ACB_DISABLED
) {
124 DEBUG(1,("authsam_account_ok: Account for user '%s' was disabled.\n", user_info
->mapped
.account_name
));
125 return NT_STATUS_ACCOUNT_DISABLED
;
128 /* Quit if the account was locked out. */
129 if (acct_flags
& ACB_AUTOLOCK
) {
130 DEBUG(1,("authsam_account_ok: Account for user %s was locked out.\n", user_info
->mapped
.account_name
));
131 return NT_STATUS_ACCOUNT_LOCKED_OUT
;
134 /* Test account expire time */
135 unix_to_nt_time(&now
, time(NULL
));
136 if (now
> acct_expiry
) {
137 DEBUG(1,("authsam_account_ok: Account for user '%s' has expired.\n", user_info
->mapped
.account_name
));
138 DEBUG(3,("authsam_account_ok: Account expired at '%s'.\n",
139 nt_time_string(mem_ctx
, acct_expiry
)));
140 return NT_STATUS_ACCOUNT_EXPIRED
;
143 if (!(acct_flags
& ACB_PWNOEXP
)) {
144 /* check for immediate expiry "must change at next logon" */
145 if (must_change_time
== 0 && last_set_time
!= 0) {
146 DEBUG(1,("sam_account_ok: Account for user '%s' password must change!.\n",
147 user_info
->mapped
.account_name
));
148 return NT_STATUS_PASSWORD_MUST_CHANGE
;
151 /* check for expired password */
152 if ((must_change_time
!= 0) && (must_change_time
< now
)) {
153 DEBUG(1,("sam_account_ok: Account for user '%s' password expired!.\n",
154 user_info
->mapped
.account_name
));
155 DEBUG(1,("sam_account_ok: Password expired at '%s' unix time.\n",
156 nt_time_string(mem_ctx
, must_change_time
)));
157 return NT_STATUS_PASSWORD_EXPIRED
;
161 /* Test workstation. Workstation list is comma separated. */
162 if (workstation_list
&& *workstation_list
) {
163 BOOL invalid_ws
= True
;
164 const char *s
= workstation_list
;
168 while (next_token(&s
, tok
, ",", sizeof(tok
))) {
169 DEBUG(10,("sam_account_ok: checking for workstation match '%s' and '%s'\n",
170 tok
, user_info
->workstation_name
));
172 if (strequal(tok
, user_info
->workstation_name
)) {
180 return NT_STATUS_INVALID_WORKSTATION
;
184 if (acct_flags
& ACB_DOMTRUST
) {
185 DEBUG(2,("sam_account_ok: Domain trust account %s denied by server\n", user_info
->mapped
.account_name
));
186 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT
;
189 if (acct_flags
& ACB_SVRTRUST
) {
190 DEBUG(2,("sam_account_ok: Server trust account %s denied by server\n", user_info
->mapped
.account_name
));
191 return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT
;
194 if (acct_flags
& ACB_WSTRUST
) {
195 DEBUG(4,("sam_account_ok: Wksta trust account %s denied by server\n", user_info
->mapped
.account_name
));
196 return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
;
202 /****************************************************************************
203 Look for the specified user in the sam, return ldb result structures
204 ****************************************************************************/
206 static NTSTATUS
authsam_search_account(TALLOC_CTX
*mem_ctx
, struct ldb_context
*sam_ctx
,
207 const char *account_name
,
208 const char *domain_name
,
209 struct ldb_message
***ret_msgs
,
210 struct ldb_message
***ret_msgs_domain
)
212 struct ldb_message
**msgs_tmp
;
213 struct ldb_message
**msgs
;
214 struct ldb_message
**msgs_domain
;
219 const struct ldb_dn
*domain_dn
= NULL
;
221 const char *attrs
[] = {"unicodePwd", "lmPwdHash", "ntPwdHash",
222 "userAccountControl",
228 /* required for server_info, not access control: */
244 const char *domain_attrs
[] = {"nETBIOSName", "nCName", NULL
};
247 /* find the domain's DN */
248 ret_domain
= gendb_search(sam_ctx
, mem_ctx
, NULL
, &msgs_domain
, domain_attrs
,
249 "(&(&(|(&(dnsRoot=%s)(nETBIOSName=*))(nETBIOSName=%s))(objectclass=crossRef))(ncName=*))",
250 domain_name
, domain_name
);
251 if (ret_domain
== -1) {
252 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
255 if (ret_domain
== 0) {
256 DEBUG(3,("sam_search_user: Couldn't find domain [%s] in samdb.\n",
258 return NT_STATUS_NO_SUCH_USER
;
261 if (ret_domain
> 1) {
262 DEBUG(0,("Found %d records matching domain [%s]\n",
263 ret_domain
, domain_name
));
264 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
267 domain_dn
= samdb_result_dn(mem_ctx
, msgs_domain
[0], "nCName", NULL
);
270 /* pull the user attributes */
271 ret
= gendb_search(sam_ctx
, mem_ctx
, domain_dn
, &msgs
, attrs
,
272 "(&(sAMAccountName=%s)(objectclass=user))",
275 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
279 DEBUG(3,("sam_search_user: Couldn't find user [%s] in samdb.\n",
281 return NT_STATUS_NO_SUCH_USER
;
285 DEBUG(0,("Found %d records matching user [%s]\n", ret
, account_name
));
286 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
290 struct dom_sid
*domain_sid
;
292 domain_sid
= samdb_result_sid_prefix(mem_ctx
, msgs
[0], "objectSid");
294 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
297 /* find the domain's DN */
298 ret
= gendb_search(sam_ctx
, mem_ctx
, NULL
, &msgs_tmp
, NULL
,
299 "(&(objectSid=%s)(objectclass=domain))",
300 ldap_encode_ndr_dom_sid(mem_ctx
, domain_sid
));
302 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
306 DEBUG(3,("check_sam_security: Couldn't find domain_sid [%s] in passdb file.\n",
307 dom_sid_string(mem_ctx
, domain_sid
)));
308 return NT_STATUS_NO_SUCH_USER
;
312 DEBUG(0,("Found %d records matching domain_sid [%s]\n",
313 ret
, dom_sid_string(mem_ctx
, domain_sid
)));
314 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
317 ret_domain
= gendb_search(sam_ctx
, mem_ctx
, NULL
, &msgs_domain
, domain_attrs
,
318 "(nCName=%s)", ldb_dn_linearize(msgs_tmp
, msgs_tmp
[0]->dn
));
320 if (ret_domain
== -1) {
321 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
324 if (ret_domain
== 0) {
325 DEBUG(3,("check_sam_security: Couldn't find domain [%s] in passdb file.\n",
326 ldb_dn_linearize(msgs_tmp
, msgs_tmp
[0]->dn
)));
327 return NT_STATUS_NO_SUCH_USER
;
330 if (ret_domain
> 1) {
331 DEBUG(0,("Found %d records matching domain [%s]\n",
332 ret_domain
, ldb_dn_linearize(msgs_tmp
, msgs_tmp
[0]->dn
)));
333 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
339 *ret_msgs_domain
= msgs_domain
;
344 static NTSTATUS
authsam_authenticate(struct auth_context
*auth_context
,
345 TALLOC_CTX
*mem_ctx
, struct ldb_context
*sam_ctx
,
346 struct ldb_message
**msgs
,
347 struct ldb_message
**msgs_domain
,
348 const struct auth_usersupplied_info
*user_info
,
349 DATA_BLOB
*user_sess_key
, DATA_BLOB
*lm_sess_key
)
352 const char *workstation_list
;
354 NTTIME must_change_time
;
355 NTTIME last_set_time
;
356 struct samr_Password
*lm_pwd
, *nt_pwd
;
358 struct ldb_dn
*domain_dn
= samdb_result_dn(mem_ctx
, msgs_domain
[0], "nCName", ldb_dn_new(mem_ctx
));
360 acct_flags
= samdb_result_acct_flags(msgs
[0], "userAccountControl");
362 /* Quit if the account was locked out. */
363 if (acct_flags
& ACB_AUTOLOCK
) {
364 DEBUG(3,("check_sam_security: Account for user %s was locked out.\n",
365 user_info
->mapped
.account_name
));
366 return NT_STATUS_ACCOUNT_LOCKED_OUT
;
369 nt_status
= samdb_result_passwords(mem_ctx
, msgs
[0], &lm_pwd
, &nt_pwd
);
370 NT_STATUS_NOT_OK_RETURN(nt_status
);
372 nt_status
= authsam_password_ok(auth_context
, mem_ctx
,
373 acct_flags
, lm_pwd
, nt_pwd
,
374 user_info
, user_sess_key
, lm_sess_key
);
375 NT_STATUS_NOT_OK_RETURN(nt_status
);
377 acct_expiry
= samdb_result_nttime(msgs
[0], "accountExpires", 0);
378 must_change_time
= samdb_result_force_password_change(sam_ctx
, mem_ctx
,
381 last_set_time
= samdb_result_nttime(msgs
[0], "pwdLastSet", 0);
383 workstation_list
= samdb_result_string(msgs
[0], "userWorkstations", NULL
);
385 nt_status
= authsam_account_ok(mem_ctx
, acct_flags
,
395 static NTSTATUS
authsam_make_server_info(TALLOC_CTX
*mem_ctx
, struct ldb_context
*sam_ctx
,
396 struct ldb_message
**msgs
,
397 struct ldb_message
**msgs_domain
,
398 DATA_BLOB user_sess_key
, DATA_BLOB lm_sess_key
,
399 struct auth_serversupplied_info
**_server_info
)
401 struct auth_serversupplied_info
*server_info
;
402 struct ldb_message
**group_msgs
;
404 const char *group_attrs
[3] = { "sAMAccountType", "objectSid", NULL
};
405 /* find list of sids */
406 struct dom_sid
**groupSIDs
= NULL
;
407 struct dom_sid
*account_sid
;
408 struct dom_sid
*primary_group_sid
;
410 struct ldb_dn
*ncname
;
413 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
415 group_ret
= gendb_search(sam_ctx
,
416 tmp_ctx
, NULL
, &group_msgs
, group_attrs
,
417 "(&(member=%s)(sAMAccountType=*))",
418 ldb_dn_linearize(tmp_ctx
, msgs
[0]->dn
));
419 if (group_ret
== -1) {
420 talloc_free(tmp_ctx
);
421 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
424 server_info
= talloc(mem_ctx
, struct auth_serversupplied_info
);
425 NT_STATUS_HAVE_NO_MEMORY(server_info
);
428 groupSIDs
= talloc_array(server_info
, struct dom_sid
*, group_ret
);
429 NT_STATUS_HAVE_NO_MEMORY(groupSIDs
);
432 /* Need to unroll some nested groups, but not aliases */
433 for (i
= 0; i
< group_ret
; i
++) {
434 groupSIDs
[i
] = samdb_result_dom_sid(groupSIDs
,
435 group_msgs
[i
], "objectSid");
436 NT_STATUS_HAVE_NO_MEMORY(groupSIDs
[i
]);
439 talloc_free(tmp_ctx
);
441 account_sid
= samdb_result_dom_sid(server_info
, msgs
[0], "objectSid");
442 NT_STATUS_HAVE_NO_MEMORY(account_sid
);
444 primary_group_sid
= dom_sid_dup(server_info
, account_sid
);
445 NT_STATUS_HAVE_NO_MEMORY(primary_group_sid
);
447 rid
= samdb_result_uint(msgs
[0], "primaryGroupID", ~0);
450 primary_group_sid
= groupSIDs
[0];
452 primary_group_sid
= NULL
;
455 primary_group_sid
->sub_auths
[primary_group_sid
->num_auths
-1] = rid
;
458 server_info
->account_sid
= account_sid
;
459 server_info
->primary_group_sid
= primary_group_sid
;
461 server_info
->n_domain_groups
= group_ret
;
462 server_info
->domain_groups
= groupSIDs
;
464 server_info
->account_name
= talloc_steal(server_info
, samdb_result_string(msgs
[0], "sAMAccountName", NULL
));
466 server_info
->domain_name
= talloc_steal(server_info
, samdb_result_string(msgs_domain
[0], "nETBIOSName", NULL
));
468 str
= samdb_result_string(msgs
[0], "displayName", "");
469 server_info
->full_name
= talloc_strdup(server_info
, str
);
470 NT_STATUS_HAVE_NO_MEMORY(server_info
->full_name
);
472 str
= samdb_result_string(msgs
[0], "scriptPath", "");
473 server_info
->logon_script
= talloc_strdup(server_info
, str
);
474 NT_STATUS_HAVE_NO_MEMORY(server_info
->logon_script
);
476 str
= samdb_result_string(msgs
[0], "profilePath", "");
477 server_info
->profile_path
= talloc_strdup(server_info
, str
);
478 NT_STATUS_HAVE_NO_MEMORY(server_info
->profile_path
);
480 str
= samdb_result_string(msgs
[0], "homeDirectory", "");
481 server_info
->home_directory
= talloc_strdup(server_info
, str
);
482 NT_STATUS_HAVE_NO_MEMORY(server_info
->home_directory
);
484 str
= samdb_result_string(msgs
[0], "homeDrive", "");
485 server_info
->home_drive
= talloc_strdup(server_info
, str
);
486 NT_STATUS_HAVE_NO_MEMORY(server_info
->home_drive
);
488 server_info
->last_logon
= samdb_result_nttime(msgs
[0], "lastLogon", 0);
489 server_info
->last_logoff
= samdb_result_nttime(msgs
[0], "lastLogoff", 0);
490 server_info
->acct_expiry
= samdb_result_nttime(msgs
[0], "accountExpires", 0);
491 server_info
->last_password_change
= samdb_result_nttime(msgs
[0], "pwdLastSet", 0);
493 ncname
= samdb_result_dn(mem_ctx
, msgs_domain
[0], "nCName", ldb_dn_new(mem_ctx
));
495 server_info
->allow_password_change
= samdb_result_allow_password_change(sam_ctx
, mem_ctx
,
496 ncname
, msgs
[0], "pwdLastSet");
497 server_info
->force_password_change
= samdb_result_force_password_change(sam_ctx
, mem_ctx
,
498 ncname
, msgs
[0], "pwdLastSet");
500 server_info
->logon_count
= samdb_result_uint(msgs
[0], "logonCount", 0);
501 server_info
->bad_password_count
= samdb_result_uint(msgs
[0], "badPwdCount", 0);
503 server_info
->acct_flags
= samdb_result_acct_flags(msgs
[0], "userAccountControl");
505 server_info
->user_session_key
= user_sess_key
;
506 server_info
->lm_session_key
= lm_sess_key
;
508 server_info
->authenticated
= True
;
510 *_server_info
= server_info
;
515 NTSTATUS
sam_get_server_info(TALLOC_CTX
*mem_ctx
, const char *account_name
, const char *domain_name
,
516 DATA_BLOB user_sess_key
, DATA_BLOB lm_sess_key
,
517 struct auth_serversupplied_info
**server_info
)
521 struct ldb_message
**msgs
;
522 struct ldb_message
**domain_msgs
;
525 sam_ctx
= samdb_connect(mem_ctx
);
526 if (sam_ctx
== NULL
) {
527 return NT_STATUS_INVALID_SYSTEM_SERVICE
;
530 nt_status
= authsam_search_account(mem_ctx
, sam_ctx
, account_name
, domain_name
, &msgs
, &domain_msgs
);
531 NT_STATUS_NOT_OK_RETURN(nt_status
);
533 nt_status
= authsam_make_server_info(mem_ctx
, sam_ctx
, msgs
, domain_msgs
,
534 user_sess_key
, lm_sess_key
,
536 NT_STATUS_NOT_OK_RETURN(nt_status
);
539 talloc_free(domain_msgs
);
544 static NTSTATUS
authsam_check_password_internals(struct auth_method_context
*ctx
,
547 const struct auth_usersupplied_info
*user_info
,
548 struct auth_serversupplied_info
**server_info
)
551 const char *account_name
= user_info
->mapped
.account_name
;
552 struct ldb_message
**msgs
;
553 struct ldb_message
**domain_msgs
;
554 struct ldb_context
*sam_ctx
;
555 DATA_BLOB user_sess_key
, lm_sess_key
;
557 if (!account_name
|| !*account_name
) {
559 return NT_STATUS_NOT_IMPLEMENTED
;
562 sam_ctx
= samdb_connect(mem_ctx
);
563 if (sam_ctx
== NULL
) {
564 return NT_STATUS_INVALID_SYSTEM_SERVICE
;
567 nt_status
= authsam_search_account(mem_ctx
, sam_ctx
, account_name
, domain
, &msgs
, &domain_msgs
);
568 NT_STATUS_NOT_OK_RETURN(nt_status
);
570 nt_status
= authsam_authenticate(ctx
->auth_ctx
, mem_ctx
, sam_ctx
, msgs
, domain_msgs
, user_info
,
571 &user_sess_key
, &lm_sess_key
);
572 NT_STATUS_NOT_OK_RETURN(nt_status
);
574 nt_status
= authsam_make_server_info(mem_ctx
, sam_ctx
, msgs
, domain_msgs
,
575 user_sess_key
, lm_sess_key
,
577 NT_STATUS_NOT_OK_RETURN(nt_status
);
580 talloc_free(domain_msgs
);
585 static NTSTATUS
authsam_ignoredomain_check_password(struct auth_method_context
*ctx
,
587 const struct auth_usersupplied_info
*user_info
,
588 struct auth_serversupplied_info
**server_info
)
590 return authsam_check_password_internals(ctx
, mem_ctx
, NULL
, user_info
, server_info
);
593 /****************************************************************************
594 Check SAM security (above) but with a few extra checks.
595 ****************************************************************************/
596 static NTSTATUS
authsam_check_password(struct auth_method_context
*ctx
,
598 const struct auth_usersupplied_info
*user_info
,
599 struct auth_serversupplied_info
**server_info
)
602 BOOL is_local_name
, is_my_domain
;
604 is_local_name
= is_myname(user_info
->mapped
.domain_name
);
605 is_my_domain
= strequal(user_info
->mapped
.domain_name
, lp_workgroup());
607 /* check whether or not we service this domain/workgroup name */
608 switch (lp_server_role()) {
609 case ROLE_STANDALONE
:
610 domain
= lp_netbios_name();
612 case ROLE_DOMAIN_MEMBER
:
613 if (!is_local_name
) {
614 DEBUG(6,("authsam_check_password: %s is not one of my local names (%s)\n",
615 user_info
->mapped
.domain_name
, (lp_server_role() == ROLE_DOMAIN_MEMBER
616 ? "ROLE_DOMAIN_MEMBER" : "ROLE_STANDALONE") ));
617 return NT_STATUS_NOT_IMPLEMENTED
;
619 domain
= lp_netbios_name();
621 case ROLE_DOMAIN_PDC
:
622 case ROLE_DOMAIN_BDC
:
623 if (!is_local_name
&& !is_my_domain
) {
624 DEBUG(6,("authsam_check_password: %s is not one of my local names or domain name (DC)\n",
625 user_info
->mapped
.domain_name
));
626 return NT_STATUS_NOT_IMPLEMENTED
;
628 domain
= lp_workgroup();
631 DEBUG(6,("authsam_check_password: lp_server_role() has an undefined value\n"));
632 return NT_STATUS_NOT_IMPLEMENTED
;
635 return authsam_check_password_internals(ctx
, mem_ctx
, domain
, user_info
, server_info
);
638 static const struct auth_operations sam_ignoredomain_ops
= {
639 .name
= "sam_ignoredomain",
640 .get_challenge
= auth_get_challenge_not_implemented
,
641 .check_password
= authsam_ignoredomain_check_password
644 static const struct auth_operations sam_ops
= {
646 .get_challenge
= auth_get_challenge_not_implemented
,
647 .check_password
= authsam_check_password
650 NTSTATUS
auth_sam_init(void)
654 ret
= auth_register(&sam_ops
);
655 if (!NT_STATUS_IS_OK(ret
)) {
656 DEBUG(0,("Failed to register 'sam' auth backend!\n"));
660 ret
= auth_register(&sam_ignoredomain_ops
);
661 if (!NT_STATUS_IS_OK(ret
)) {
662 DEBUG(0,("Failed to register 'sam_ignoredomain' auth backend!\n"));