2 Unix SMB/CIFS implementation.
3 Password and authentication handling
4 Copyright (C) Andrew Bartlett 2001
5 Copyright (C) Jeremy Allison 2001
6 Copyright (C) Simo Sorce 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 3 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, see <http://www.gnu.org/licenses/>.
23 #include "auth/auth.h"
24 #include "system/passwd.h" /* needed by some systems for struct passwd */
25 #include "lib/socket/socket.h"
26 #include "auth/pam_errors.h"
27 #include "param/param.h"
29 /* TODO: look at how to best fill in parms retrieveing a struct passwd info
30 * except in case USER_INFO_DONT_CHECK_UNIX_ACCOUNT is set
32 static NTSTATUS authunix_make_server_info(TALLOC_CTX *mem_ctx,
33 const struct auth_usersupplied_info *user_info,
35 struct auth_serversupplied_info **_server_info)
37 struct auth_serversupplied_info *server_info;
40 /* This is a real, real hack */
41 if (pwd->pw_uid == 0) {
42 status = auth_system_server_info(mem_ctx, &server_info);
43 if (!NT_STATUS_IS_OK(status)) {
47 server_info->account_name = talloc_steal(server_info, pwd->pw_name);
48 NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
50 server_info->domain_name = talloc_strdup(server_info, "unix");
51 NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
53 server_info = talloc(mem_ctx, struct auth_serversupplied_info);
54 NT_STATUS_HAVE_NO_MEMORY(server_info);
56 server_info->authenticated = true;
58 server_info->account_name = talloc_steal(server_info, pwd->pw_name);
59 NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
61 server_info->domain_name = talloc_strdup(server_info, "unix");
62 NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
64 /* This isn't in any way correct.. */
65 server_info->account_sid = NULL;
66 server_info->primary_group_sid = NULL;
67 server_info->n_domain_groups = 0;
68 server_info->domain_groups = NULL;
70 server_info->user_session_key = data_blob(NULL,0);
71 server_info->lm_session_key = data_blob(NULL,0);
73 server_info->full_name = talloc_steal(server_info, pwd->pw_gecos);
74 NT_STATUS_HAVE_NO_MEMORY(server_info->full_name);
75 server_info->logon_script = talloc_strdup(server_info, "");
76 NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script);
77 server_info->profile_path = talloc_strdup(server_info, "");
78 NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path);
79 server_info->home_directory = talloc_strdup(server_info, "");
80 NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory);
81 server_info->home_drive = talloc_strdup(server_info, "");
82 NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive);
84 server_info->last_logon = 0;
85 server_info->last_logoff = 0;
86 server_info->acct_expiry = 0;
87 server_info->last_password_change = 0;
88 server_info->allow_password_change = 0;
89 server_info->force_password_change = 0;
90 server_info->logon_count = 0;
91 server_info->bad_password_count = 0;
92 server_info->acct_flags = 0;
94 *_server_info = server_info;
99 static NTSTATUS talloc_getpwnam(TALLOC_CTX *ctx, const char *username, struct passwd **pws)
106 ret = talloc(ctx, struct passwd);
107 NT_STATUS_HAVE_NO_MEMORY(ret);
109 from = getpwnam(username);
111 return NT_STATUS_NO_SUCH_USER;
114 ret->pw_name = talloc_strdup(ctx, from->pw_name);
115 NT_STATUS_HAVE_NO_MEMORY(ret->pw_name);
117 ret->pw_passwd = talloc_strdup(ctx, from->pw_passwd);
118 NT_STATUS_HAVE_NO_MEMORY(ret->pw_passwd);
120 ret->pw_uid = from->pw_uid;
121 ret->pw_gid = from->pw_gid;
122 ret->pw_gecos = talloc_strdup(ctx, from->pw_gecos);
123 NT_STATUS_HAVE_NO_MEMORY(ret->pw_gecos);
125 ret->pw_dir = talloc_strdup(ctx, from->pw_dir);
126 NT_STATUS_HAVE_NO_MEMORY(ret->pw_dir);
128 ret->pw_shell = talloc_strdup(ctx, from->pw_shell);
129 NT_STATUS_HAVE_NO_MEMORY(ret->pw_shell);
137 #ifdef HAVE_SECURITY_PAM_APPL_H
138 #include <security/pam_appl.h>
140 struct smb_pam_user_info {
141 const char *account_name;
142 const char *plaintext_password;
145 #define COPY_STRING(s) (s) ? strdup(s) : NULL
148 * Check user password
149 * Currently it uses PAM only and fails on systems without PAM
150 * Samba3 code located in pass_check.c is to ugly to be used directly it will
151 * need major rework that's why pass_check.c is still there.
154 static int smb_pam_conv(int num_msg, const struct pam_message **msg,
155 struct pam_response **reply, void *appdata_ptr)
157 struct smb_pam_user_info *info = (struct smb_pam_user_info *)appdata_ptr;
166 * Apparantly HPUX has a buggy PAM that doesn't support the
167 * data pointer. Fail if this is the case. JRA.
176 * PAM frees memory in reply messages by itself
177 * so use malloc instead of talloc here.
179 *reply = malloc_array_p(struct pam_response, num_msg);
180 if (*reply == NULL) {
184 for (num = 0; num < num_msg; num++) {
185 switch (msg[num]->msg_style) {
186 case PAM_PROMPT_ECHO_ON:
187 (*reply)[num].resp_retcode = PAM_SUCCESS;
188 (*reply)[num].resp = COPY_STRING(info->account_name);
191 case PAM_PROMPT_ECHO_OFF:
192 (*reply)[num].resp_retcode = PAM_SUCCESS;
193 (*reply)[num].resp = COPY_STRING(info->plaintext_password);
197 (*reply)[num].resp_retcode = PAM_SUCCESS;
198 (*reply)[num].resp = NULL;
199 DEBUG(4,("PAM Info message in conversation function: %s\n", (msg[num]->msg)));
203 (*reply)[num].resp_retcode = PAM_SUCCESS;
204 (*reply)[num].resp = NULL;
205 DEBUG(4,("PAM Error message in conversation function: %s\n", (msg[num]->msg)));
210 SAFE_FREE((*reply)[num-1].resp);
215 DEBUG(1,("Error: PAM subsystme sent an UNKNOWN message type to the conversation function!\n"));
224 * Start PAM authentication for specified account
227 static NTSTATUS smb_pam_start(pam_handle_t **pamh, const char *account_name, const char *remote_host, struct pam_conv *pconv)
231 if (account_name == NULL || remote_host == NULL) {
232 return NT_STATUS_INVALID_PARAMETER;
235 DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", account_name));
237 pam_error = pam_start("samba", account_name, pconv, pamh);
238 if (pam_error != PAM_SUCCESS) {
239 /* no valid pamh here, can we reliably call pam_strerror ? */
240 DEBUG(4,("smb_pam_start: pam_start failed!\n"));
241 return NT_STATUS_UNSUCCESSFUL;
245 DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", remote_host));
246 pam_error = pam_set_item(*pamh, PAM_RHOST, remote_host);
247 if (pam_error != PAM_SUCCESS) {
250 DEBUG(4,("smb_pam_start: setting rhost failed with error: %s\n",
251 pam_strerror(*pamh, pam_error)));
252 nt_status = pam_to_nt_status(pam_error);
254 pam_error = pam_end(*pamh, 0);
255 if (pam_error != PAM_SUCCESS) {
256 /* no vaild pamh here, can we reliably call pam_strerror ? */
257 DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
259 return pam_to_nt_status(pam_error);
265 DEBUG(4,("smb_pam_start: PAM: setting tty\n"));
266 pam_error = pam_set_item(*pamh, PAM_TTY, "samba");
267 if (pam_error != PAM_SUCCESS) {
270 DEBUG(4,("smb_pam_start: setting tty failed with error: %s\n",
271 pam_strerror(*pamh, pam_error)));
272 nt_status = pam_to_nt_status(pam_error);
274 pam_error = pam_end(*pamh, 0);
275 if (pam_error != PAM_SUCCESS) {
276 /* no vaild pamh here, can we reliably call pam_strerror ? */
277 DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
279 return pam_to_nt_status(pam_error);
284 DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", account_name));
289 static NTSTATUS smb_pam_end(pam_handle_t *pamh)
294 pam_error = pam_end(pamh, 0);
295 if (pam_error != PAM_SUCCESS) {
296 /* no vaild pamh here, can we reliably call pam_strerror ? */
297 DEBUG(4,("smb_pam_end: clean up failed, pam_end gave error %d.\n",
299 return pam_to_nt_status(pam_error);
304 DEBUG(2,("smb_pam_end: pamh is NULL, PAM not initialized ?\n"));
305 return NT_STATUS_UNSUCCESSFUL;
309 * PAM Authentication Handler
311 static NTSTATUS smb_pam_auth(pam_handle_t *pamh, const char *user)
316 * To enable debugging set in /etc/pam.d/samba:
317 * auth required /lib/security/pam_pwdb.so nullok shadow audit
320 DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user));
322 pam_error = pam_authenticate(pamh, PAM_SILENT | lp_null_passwords(global_loadparm) ? 0 : PAM_DISALLOW_NULL_AUTHTOK);
325 DEBUG(2, ("smb_pam_auth: PAM: Authentication Error for user %s\n", user));
327 case PAM_CRED_INSUFFICIENT:
328 DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user));
330 case PAM_AUTHINFO_UNAVAIL:
331 DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user));
333 case PAM_USER_UNKNOWN:
334 DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user));
337 DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user));
340 DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user));
343 DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user));
346 DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user));
350 return pam_to_nt_status(pam_error);
354 * PAM Account Handler
356 static NTSTATUS smb_pam_account(pam_handle_t *pamh, const char * user)
360 DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user));
362 pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
363 switch( pam_error ) {
364 case PAM_AUTHTOK_EXPIRED:
365 DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user));
367 case PAM_ACCT_EXPIRED:
368 DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user));
371 DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user));
373 case PAM_PERM_DENIED:
374 DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user));
376 case PAM_USER_UNKNOWN:
377 DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user));
380 DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user));
383 DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user));
387 return pam_to_nt_status(pam_error);
391 * PAM Credential Setting
394 static NTSTATUS smb_pam_setcred(pam_handle_t *pamh, const char * user)
399 * This will allow samba to aquire a kerberos token. And, when
400 * exporting an AFS cell, be able to /write/ to this cell.
403 DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user));
405 pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT));
406 switch( pam_error ) {
407 case PAM_CRED_UNAVAIL:
408 DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user ));
410 case PAM_CRED_EXPIRED:
411 DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user ));
413 case PAM_USER_UNKNOWN:
414 DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user ));
417 DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user ));
420 DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user));
423 DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user));
427 return pam_to_nt_status(pam_error);
430 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, struct loadparm_context *lp_ctx,
431 const struct auth_usersupplied_info *user_info, struct passwd **pws)
433 struct smb_pam_user_info *info;
434 struct pam_conv *pamconv;
438 info = talloc(ctx, struct smb_pam_user_info);
440 return NT_STATUS_NO_MEMORY;
443 info->account_name = user_info->mapped.account_name;
444 info->plaintext_password = user_info->password.plaintext;
446 pamconv = talloc(ctx, struct pam_conv);
447 if (pamconv == NULL) {
448 return NT_STATUS_NO_MEMORY;
451 pamconv->conv = smb_pam_conv;
452 pamconv->appdata_ptr = (void *)info;
455 * check for user_info->flags & USER_INFO_CASE_INSENSITIVE_USERNAME
456 * if true set up a crack name routine.
459 nt_status = smb_pam_start(&pamh, user_info->mapped.account_name, user_info->remote_host ? user_info->remote_host->addr : NULL, pamconv);
460 if (!NT_STATUS_IS_OK(nt_status)) {
464 nt_status = smb_pam_auth(pamh, user_info->mapped.account_name);
465 if (!NT_STATUS_IS_OK(nt_status)) {
470 if ( ! (user_info->flags & USER_INFO_DONT_CHECK_UNIX_ACCOUNT)) {
472 nt_status = smb_pam_account(pamh, user_info->mapped.account_name);
473 if (!NT_STATUS_IS_OK(nt_status)) {
478 nt_status = smb_pam_setcred(pamh, user_info->mapped.account_name);
479 if (!NT_STATUS_IS_OK(nt_status)) {
487 nt_status = talloc_getpwnam(ctx, user_info->mapped.account_name, pws);
488 if (!NT_STATUS_IS_OK(nt_status)) {
497 /****************************************************************************
498 core of password checking routine
499 ****************************************************************************/
500 static NTSTATUS password_check(const char *username, const char *password,
501 const char *crypted, const char *salt)
506 if (afs_auth(username, password))
508 #endif /* WITH_AFS */
511 if (dfs_auth(username, password))
513 #endif /* WITH_DFS */
517 ret = (strcmp(osf1_bigcrypt(password, salt), crypted) == 0);
521 ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
522 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
527 return NT_STATUS_WRONG_PASSWORD;
530 #endif /* OSF1_ENH_SEC */
533 ret = (strcmp((char *)crypt16(password, salt), crypted) == 0);
537 return NT_STATUS_WRONG_PASSWORD;
540 #endif /* ULTRIX_AUTH */
542 #ifdef LINUX_BIGCRYPT
543 ret = (linux_bigcrypt(password, salt, crypted));
547 return NT_STATUS_WRONG_PASSWORD;
549 #endif /* LINUX_BIGCRYPT */
551 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
554 * Some systems have bigcrypt in the C library but might not
555 * actually use it for the password hashes (HPUX 10.20) is
556 * a noteable example. So we try bigcrypt first, followed
560 if (strcmp(bigcrypt(password, salt), crypted) == 0)
563 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
567 return NT_STATUS_WRONG_PASSWORD;
569 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
572 ret = (strcmp(bigcrypt(password, salt), crypted) == 0);
576 return NT_STATUS_WRONG_PASSWORD;
578 #endif /* HAVE_BIGCRYPT */
581 DEBUG(1, ("Warning - no crypt available\n"));
582 return NT_STATUS_LOGON_FAILURE;
583 #else /* HAVE_CRYPT */
584 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
588 return NT_STATUS_WRONG_PASSWORD;
590 #endif /* HAVE_CRYPT */
591 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
594 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, struct loadparm_context *lp_ctx,
595 const struct auth_usersupplied_info *user_info, struct passwd **ret_passwd)
604 int level = lp_passwordlevel(lp_ctx);
608 username = talloc_strdup(ctx, user_info->mapped.account_name);
609 password = talloc_strdup(ctx, user_info->password.plaintext);
611 nt_status = talloc_getpwnam(ctx, username, &pws);
612 if (!NT_STATUS_IS_OK(nt_status)) {
616 crypted = pws->pw_passwd;
617 salt = pws->pw_passwd;
623 /* many shadow systems require you to be root to get
624 the password, in most cases this should already be
625 the case when this function is called, except
626 perhaps for IPC password changing requests */
628 spass = getspnam(pws->pw_name);
629 if (spass && spass->sp_pwdp) {
630 crypted = talloc_strdup(ctx, spass->sp_pwdp);
631 NT_STATUS_HAVE_NO_MEMORY(crypted);
632 salt = talloc_strdup(ctx, spass->sp_pwdp);
633 NT_STATUS_HAVE_NO_MEMORY(salt);
636 #elif defined(IA_UINFO)
639 /* Need to get password with SVR4.2's ia_ functions
640 instead of get{sp,pw}ent functions. Required by
641 UnixWare 2.x, tested on version
642 2.1. (tangent@cyberport.com) */
644 if (ia_openinfo(pws->pw_name, &uinfo) != -1) {
645 ia_get_logpwd(uinfo, &ia_password);
646 crypted = talloc_strdup(ctx, ia_password);
647 NT_STATUS_HAVE_NO_MEMORY(crypted);
652 #ifdef HAVE_GETPRPWNAM
654 struct pr_passwd *pr_pw = getprpwnam(pws->pw_name);
655 if (pr_pw && pr_pw->ufld.fd_encrypt) {
656 crypted = talloc_strdup(ctx, pr_pw->ufld.fd_encrypt);
657 NT_STATUS_HAVE_NO_MEMORY(crypted);
662 #ifdef HAVE_GETPWANAM
664 struct passwd_adjunct *pwret;
665 pwret = getpwanam(s);
666 if (pwret && pwret->pwa_passwd) {
667 crypted = talloc_strdup(ctx, pwret->pwa_passwd);
668 NT_STATUS_HAVE_NO_MEMORY(crypted);
675 struct pr_passwd *mypasswd;
676 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n", username));
677 mypasswd = getprpwnam(username);
679 username = talloc_strdup(ctx, mypasswd->ufld.fd_name);
680 NT_STATUS_HAVE_NO_MEMORY(username);
681 crypted = talloc_strdup(ctx, mypasswd->ufld.fd_encrypt);
682 NT_STATUS_HAVE_NO_MEMORY(crypted);
684 DEBUG(5,("OSF1_ENH_SEC: No entry for user %s in protected database !\n", username));
691 AUTHORIZATION *ap = getauthuid(pws->pw_uid);
693 crypted = talloc_strdup(ctx, ap->a_password);
695 NT_STATUS_HAVE_NO_MEMORY(crypted);
700 #if defined(HAVE_TRUNCATED_SALT)
701 /* crypt on some platforms (HPUX in particular)
702 won't work with more than 2 salt characters. */
706 if (crypted[0] == '\0') {
707 if (!lp_null_passwords(lp_ctx)) {
708 DEBUG(2, ("Disallowing %s with null password\n", username));
709 return NT_STATUS_LOGON_FAILURE;
711 if (password == NULL) {
712 DEBUG(3, ("Allowing access to %s with null password\n", username));
718 /* try it as it came to us */
719 nt_status = password_check(username, password, crypted, salt);
720 if (NT_STATUS_IS_OK(nt_status)) {
724 else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
725 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
729 if ( user_info->flags | USER_INFO_CASE_INSENSITIVE_PASSWORD) {
733 /* if the password was given to us with mixed case then we don't
734 * need to proceed as we know it hasn't been case modified by the
736 if (strhasupper(password) && strhaslower(password)) {
740 /* make a copy of it */
741 pwcopy = talloc_strdup(ctx, password);
743 return NT_STATUS_NO_MEMORY;
745 /* try all lowercase if it's currently all uppercase */
746 if (strhasupper(pwcopy)) {
748 nt_status = password_check(username, pwcopy, crypted, salt);
749 if NT_STATUS_IS_OK(nt_status) {
757 return NT_STATUS_WRONG_PASSWORD;
760 /* last chance - all combinations of up to level chars upper! */
764 if (NT_STATUS_IS_OK(nt_status = string_combinations(pwcopy, password_check, level))) {
769 return NT_STATUS_WRONG_PASSWORD;
774 /** Check a plaintext username/password
778 static NTSTATUS authunix_want_check(struct auth_method_context *ctx,
780 const struct auth_usersupplied_info *user_info)
782 if (!user_info->mapped.account_name || !*user_info->mapped.account_name) {
783 return NT_STATUS_NOT_IMPLEMENTED;
789 static NTSTATUS authunix_check_password(struct auth_method_context *ctx,
791 const struct auth_usersupplied_info *user_info,
792 struct auth_serversupplied_info **server_info)
794 TALLOC_CTX *check_ctx;
798 if (user_info->password_state != AUTH_PASSWORD_PLAIN) {
799 return NT_STATUS_INVALID_PARAMETER;
802 check_ctx = talloc_named_const(mem_ctx, 0, "check_unix_password");
803 if (check_ctx == NULL) {
804 return NT_STATUS_NO_MEMORY;
807 nt_status = check_unix_password(check_ctx, ctx->auth_ctx->lp_ctx, user_info, &pwd);
808 if (!NT_STATUS_IS_OK(nt_status)) {
809 talloc_free(check_ctx);
813 nt_status = authunix_make_server_info(mem_ctx, user_info, pwd, server_info);
814 if (!NT_STATUS_IS_OK(nt_status)) {
815 talloc_free(check_ctx);
819 talloc_free(check_ctx);
823 static const struct auth_operations unix_ops = {
825 .get_challenge = auth_get_challenge_not_implemented,
826 .want_check = authunix_want_check,
827 .check_password = authunix_check_password
830 NTSTATUS auth_unix_init(void)
834 ret = auth_register(&unix_ops);
835 if (!NT_STATUS_IS_OK(ret)) {
836 DEBUG(0,("Failed to register unix auth backend!\n"));