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 char *netbios_name,
34 const struct auth_usersupplied_info *user_info,
36 struct auth_serversupplied_info **_server_info)
38 struct auth_serversupplied_info *server_info;
41 /* This is a real, real hack */
42 if (pwd->pw_uid == 0) {
43 status = auth_system_server_info(mem_ctx, netbios_name, &server_info);
44 if (!NT_STATUS_IS_OK(status)) {
48 server_info->account_name = talloc_steal(server_info, pwd->pw_name);
49 NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
51 server_info->domain_name = talloc_strdup(server_info, "unix");
52 NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
54 server_info = talloc(mem_ctx, struct auth_serversupplied_info);
55 NT_STATUS_HAVE_NO_MEMORY(server_info);
57 server_info->authenticated = true;
59 server_info->account_name = talloc_steal(server_info, pwd->pw_name);
60 NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
62 server_info->domain_name = talloc_strdup(server_info, "unix");
63 NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
65 /* This isn't in any way correct.. */
66 server_info->account_sid = NULL;
67 server_info->primary_group_sid = NULL;
68 server_info->n_domain_groups = 0;
69 server_info->domain_groups = NULL;
71 server_info->user_session_key = data_blob(NULL,0);
72 server_info->lm_session_key = data_blob(NULL,0);
74 server_info->full_name = talloc_steal(server_info, pwd->pw_gecos);
75 NT_STATUS_HAVE_NO_MEMORY(server_info->full_name);
76 server_info->logon_script = talloc_strdup(server_info, "");
77 NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script);
78 server_info->profile_path = talloc_strdup(server_info, "");
79 NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path);
80 server_info->home_directory = talloc_strdup(server_info, "");
81 NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory);
82 server_info->home_drive = talloc_strdup(server_info, "");
83 NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive);
85 server_info->last_logon = 0;
86 server_info->last_logoff = 0;
87 server_info->acct_expiry = 0;
88 server_info->last_password_change = 0;
89 server_info->allow_password_change = 0;
90 server_info->force_password_change = 0;
91 server_info->logon_count = 0;
92 server_info->bad_password_count = 0;
93 server_info->acct_flags = 0;
95 *_server_info = server_info;
100 static NTSTATUS talloc_getpwnam(TALLOC_CTX *ctx, const char *username, struct passwd **pws)
107 ret = talloc(ctx, struct passwd);
108 NT_STATUS_HAVE_NO_MEMORY(ret);
110 from = getpwnam(username);
112 return NT_STATUS_NO_SUCH_USER;
115 ret->pw_name = talloc_strdup(ctx, from->pw_name);
116 NT_STATUS_HAVE_NO_MEMORY(ret->pw_name);
118 ret->pw_passwd = talloc_strdup(ctx, from->pw_passwd);
119 NT_STATUS_HAVE_NO_MEMORY(ret->pw_passwd);
121 ret->pw_uid = from->pw_uid;
122 ret->pw_gid = from->pw_gid;
123 ret->pw_gecos = talloc_strdup(ctx, from->pw_gecos);
124 NT_STATUS_HAVE_NO_MEMORY(ret->pw_gecos);
126 ret->pw_dir = talloc_strdup(ctx, from->pw_dir);
127 NT_STATUS_HAVE_NO_MEMORY(ret->pw_dir);
129 ret->pw_shell = talloc_strdup(ctx, from->pw_shell);
130 NT_STATUS_HAVE_NO_MEMORY(ret->pw_shell);
138 #ifdef HAVE_SECURITY_PAM_APPL_H
139 #include <security/pam_appl.h>
141 struct smb_pam_user_info {
142 const char *account_name;
143 const char *plaintext_password;
146 #define COPY_STRING(s) (s) ? strdup(s) : NULL
149 * Check user password
150 * Currently it uses PAM only and fails on systems without PAM
151 * Samba3 code located in pass_check.c is to ugly to be used directly it will
152 * need major rework that's why pass_check.c is still there.
155 static int smb_pam_conv(int num_msg, const struct pam_message **msg,
156 struct pam_response **reply, void *appdata_ptr)
158 struct smb_pam_user_info *info = (struct smb_pam_user_info *)appdata_ptr;
167 * Apparantly HPUX has a buggy PAM that doesn't support the
168 * data pointer. Fail if this is the case. JRA.
177 * PAM frees memory in reply messages by itself
178 * so use malloc instead of talloc here.
180 *reply = malloc_array_p(struct pam_response, num_msg);
181 if (*reply == NULL) {
185 for (num = 0; num < num_msg; num++) {
186 switch (msg[num]->msg_style) {
187 case PAM_PROMPT_ECHO_ON:
188 (*reply)[num].resp_retcode = PAM_SUCCESS;
189 (*reply)[num].resp = COPY_STRING(info->account_name);
192 case PAM_PROMPT_ECHO_OFF:
193 (*reply)[num].resp_retcode = PAM_SUCCESS;
194 (*reply)[num].resp = COPY_STRING(info->plaintext_password);
198 (*reply)[num].resp_retcode = PAM_SUCCESS;
199 (*reply)[num].resp = NULL;
200 DEBUG(4,("PAM Info message in conversation function: %s\n", (msg[num]->msg)));
204 (*reply)[num].resp_retcode = PAM_SUCCESS;
205 (*reply)[num].resp = NULL;
206 DEBUG(4,("PAM Error message in conversation function: %s\n", (msg[num]->msg)));
211 SAFE_FREE((*reply)[num-1].resp);
216 DEBUG(1,("Error: PAM subsystme sent an UNKNOWN message type to the conversation function!\n"));
225 * Start PAM authentication for specified account
228 static NTSTATUS smb_pam_start(pam_handle_t **pamh, const char *account_name, const char *remote_host, struct pam_conv *pconv)
232 if (account_name == NULL || remote_host == NULL) {
233 return NT_STATUS_INVALID_PARAMETER;
236 DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", account_name));
238 pam_error = pam_start("samba", account_name, pconv, pamh);
239 if (pam_error != PAM_SUCCESS) {
240 /* no valid pamh here, can we reliably call pam_strerror ? */
241 DEBUG(4,("smb_pam_start: pam_start failed!\n"));
242 return NT_STATUS_UNSUCCESSFUL;
246 DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", remote_host));
247 pam_error = pam_set_item(*pamh, PAM_RHOST, remote_host);
248 if (pam_error != PAM_SUCCESS) {
251 DEBUG(4,("smb_pam_start: setting rhost failed with error: %s\n",
252 pam_strerror(*pamh, pam_error)));
253 nt_status = pam_to_nt_status(pam_error);
255 pam_error = pam_end(*pamh, 0);
256 if (pam_error != PAM_SUCCESS) {
257 /* no vaild pamh here, can we reliably call pam_strerror ? */
258 DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
260 return pam_to_nt_status(pam_error);
266 DEBUG(4,("smb_pam_start: PAM: setting tty\n"));
267 pam_error = pam_set_item(*pamh, PAM_TTY, "samba");
268 if (pam_error != PAM_SUCCESS) {
271 DEBUG(4,("smb_pam_start: setting tty failed with error: %s\n",
272 pam_strerror(*pamh, pam_error)));
273 nt_status = pam_to_nt_status(pam_error);
275 pam_error = pam_end(*pamh, 0);
276 if (pam_error != PAM_SUCCESS) {
277 /* no vaild pamh here, can we reliably call pam_strerror ? */
278 DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
280 return pam_to_nt_status(pam_error);
285 DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", account_name));
290 static NTSTATUS smb_pam_end(pam_handle_t *pamh)
295 pam_error = pam_end(pamh, 0);
296 if (pam_error != PAM_SUCCESS) {
297 /* no vaild pamh here, can we reliably call pam_strerror ? */
298 DEBUG(4,("smb_pam_end: clean up failed, pam_end gave error %d.\n",
300 return pam_to_nt_status(pam_error);
305 DEBUG(2,("smb_pam_end: pamh is NULL, PAM not initialized ?\n"));
306 return NT_STATUS_UNSUCCESSFUL;
310 * PAM Authentication Handler
312 static NTSTATUS smb_pam_auth(pam_handle_t *pamh, bool allow_null_passwords, const char *user)
317 * To enable debugging set in /etc/pam.d/samba:
318 * auth required /lib/security/pam_pwdb.so nullok shadow audit
321 DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user));
323 pam_error = pam_authenticate(pamh, PAM_SILENT | allow_null_passwords ? 0 : PAM_DISALLOW_NULL_AUTHTOK);
326 DEBUG(2, ("smb_pam_auth: PAM: Authentication Error for user %s\n", user));
328 case PAM_CRED_INSUFFICIENT:
329 DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user));
331 case PAM_AUTHINFO_UNAVAIL:
332 DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user));
334 case PAM_USER_UNKNOWN:
335 DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user));
338 DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user));
341 DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user));
344 DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user));
347 DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user));
351 return pam_to_nt_status(pam_error);
355 * PAM Account Handler
357 static NTSTATUS smb_pam_account(pam_handle_t *pamh, const char * user)
361 DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user));
363 pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
364 switch( pam_error ) {
365 case PAM_AUTHTOK_EXPIRED:
366 DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user));
368 case PAM_ACCT_EXPIRED:
369 DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user));
372 DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user));
374 case PAM_PERM_DENIED:
375 DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user));
377 case PAM_USER_UNKNOWN:
378 DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user));
381 DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user));
384 DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user));
388 return pam_to_nt_status(pam_error);
392 * PAM Credential Setting
395 static NTSTATUS smb_pam_setcred(pam_handle_t *pamh, const char * user)
400 * This will allow samba to aquire a kerberos token. And, when
401 * exporting an AFS cell, be able to /write/ to this cell.
404 DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user));
406 pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT));
407 switch( pam_error ) {
408 case PAM_CRED_UNAVAIL:
409 DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user ));
411 case PAM_CRED_EXPIRED:
412 DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user ));
414 case PAM_USER_UNKNOWN:
415 DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user ));
418 DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user ));
421 DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user));
424 DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user));
428 return pam_to_nt_status(pam_error);
431 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, struct loadparm_context *lp_ctx,
432 const struct auth_usersupplied_info *user_info, struct passwd **pws)
434 struct smb_pam_user_info *info;
435 struct pam_conv *pamconv;
439 info = talloc(ctx, struct smb_pam_user_info);
441 return NT_STATUS_NO_MEMORY;
444 info->account_name = user_info->mapped.account_name;
445 info->plaintext_password = user_info->password.plaintext;
447 pamconv = talloc(ctx, struct pam_conv);
448 if (pamconv == NULL) {
449 return NT_STATUS_NO_MEMORY;
452 pamconv->conv = smb_pam_conv;
453 pamconv->appdata_ptr = (void *)info;
456 * check for user_info->flags & USER_INFO_CASE_INSENSITIVE_USERNAME
457 * if true set up a crack name routine.
460 nt_status = smb_pam_start(&pamh, user_info->mapped.account_name, user_info->remote_host ? user_info->remote_host->addr : NULL, pamconv);
461 if (!NT_STATUS_IS_OK(nt_status)) {
465 nt_status = smb_pam_auth(pamh, lp_null_passwords(lp_ctx), user_info->mapped.account_name);
466 if (!NT_STATUS_IS_OK(nt_status)) {
471 if ( ! (user_info->flags & USER_INFO_DONT_CHECK_UNIX_ACCOUNT)) {
473 nt_status = smb_pam_account(pamh, user_info->mapped.account_name);
474 if (!NT_STATUS_IS_OK(nt_status)) {
479 nt_status = smb_pam_setcred(pamh, user_info->mapped.account_name);
480 if (!NT_STATUS_IS_OK(nt_status)) {
488 nt_status = talloc_getpwnam(ctx, user_info->mapped.account_name, pws);
489 if (!NT_STATUS_IS_OK(nt_status)) {
498 /****************************************************************************
499 core of password checking routine
500 ****************************************************************************/
501 static NTSTATUS password_check(const char *username, const char *password,
502 const char *crypted, const char *salt)
507 if (afs_auth(username, password))
509 #endif /* WITH_AFS */
512 if (dfs_auth(username, password))
514 #endif /* WITH_DFS */
518 ret = (strcmp(osf1_bigcrypt(password, salt), crypted) == 0);
522 ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
523 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
528 return NT_STATUS_WRONG_PASSWORD;
531 #endif /* OSF1_ENH_SEC */
534 ret = (strcmp((char *)crypt16(password, salt), crypted) == 0);
538 return NT_STATUS_WRONG_PASSWORD;
541 #endif /* ULTRIX_AUTH */
543 #ifdef LINUX_BIGCRYPT
544 ret = (linux_bigcrypt(password, salt, crypted));
548 return NT_STATUS_WRONG_PASSWORD;
550 #endif /* LINUX_BIGCRYPT */
552 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
555 * Some systems have bigcrypt in the C library but might not
556 * actually use it for the password hashes (HPUX 10.20) is
557 * a noteable example. So we try bigcrypt first, followed
561 if (strcmp(bigcrypt(password, salt), crypted) == 0)
564 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
568 return NT_STATUS_WRONG_PASSWORD;
570 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
573 ret = (strcmp(bigcrypt(password, salt), crypted) == 0);
577 return NT_STATUS_WRONG_PASSWORD;
579 #endif /* HAVE_BIGCRYPT */
582 DEBUG(1, ("Warning - no crypt available\n"));
583 return NT_STATUS_LOGON_FAILURE;
584 #else /* HAVE_CRYPT */
585 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
589 return NT_STATUS_WRONG_PASSWORD;
591 #endif /* HAVE_CRYPT */
592 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
595 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, struct loadparm_context *lp_ctx,
596 const struct auth_usersupplied_info *user_info, struct passwd **ret_passwd)
605 int level = lp_passwordlevel(lp_ctx);
609 username = talloc_strdup(ctx, user_info->mapped.account_name);
610 password = talloc_strdup(ctx, user_info->password.plaintext);
612 nt_status = talloc_getpwnam(ctx, username, &pws);
613 if (!NT_STATUS_IS_OK(nt_status)) {
617 crypted = pws->pw_passwd;
618 salt = pws->pw_passwd;
624 /* many shadow systems require you to be root to get
625 the password, in most cases this should already be
626 the case when this function is called, except
627 perhaps for IPC password changing requests */
629 spass = getspnam(pws->pw_name);
630 if (spass && spass->sp_pwdp) {
631 crypted = talloc_strdup(ctx, spass->sp_pwdp);
632 NT_STATUS_HAVE_NO_MEMORY(crypted);
633 salt = talloc_strdup(ctx, spass->sp_pwdp);
634 NT_STATUS_HAVE_NO_MEMORY(salt);
637 #elif defined(IA_UINFO)
640 /* Need to get password with SVR4.2's ia_ functions
641 instead of get{sp,pw}ent functions. Required by
642 UnixWare 2.x, tested on version
643 2.1. (tangent@cyberport.com) */
645 if (ia_openinfo(pws->pw_name, &uinfo) != -1) {
646 ia_get_logpwd(uinfo, &ia_password);
647 crypted = talloc_strdup(ctx, ia_password);
648 NT_STATUS_HAVE_NO_MEMORY(crypted);
653 #ifdef HAVE_GETPRPWNAM
655 struct pr_passwd *pr_pw = getprpwnam(pws->pw_name);
656 if (pr_pw && pr_pw->ufld.fd_encrypt) {
657 crypted = talloc_strdup(ctx, pr_pw->ufld.fd_encrypt);
658 NT_STATUS_HAVE_NO_MEMORY(crypted);
663 #ifdef HAVE_GETPWANAM
665 struct passwd_adjunct *pwret;
666 pwret = getpwanam(s);
667 if (pwret && pwret->pwa_passwd) {
668 crypted = talloc_strdup(ctx, pwret->pwa_passwd);
669 NT_STATUS_HAVE_NO_MEMORY(crypted);
676 struct pr_passwd *mypasswd;
677 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n", username));
678 mypasswd = getprpwnam(username);
680 username = talloc_strdup(ctx, mypasswd->ufld.fd_name);
681 NT_STATUS_HAVE_NO_MEMORY(username);
682 crypted = talloc_strdup(ctx, mypasswd->ufld.fd_encrypt);
683 NT_STATUS_HAVE_NO_MEMORY(crypted);
685 DEBUG(5,("OSF1_ENH_SEC: No entry for user %s in protected database !\n", username));
692 AUTHORIZATION *ap = getauthuid(pws->pw_uid);
694 crypted = talloc_strdup(ctx, ap->a_password);
696 NT_STATUS_HAVE_NO_MEMORY(crypted);
701 #if defined(HAVE_TRUNCATED_SALT)
702 /* crypt on some platforms (HPUX in particular)
703 won't work with more than 2 salt characters. */
707 if (crypted[0] == '\0') {
708 if (!lp_null_passwords(lp_ctx)) {
709 DEBUG(2, ("Disallowing %s with null password\n", username));
710 return NT_STATUS_LOGON_FAILURE;
712 if (password == NULL) {
713 DEBUG(3, ("Allowing access to %s with null password\n", username));
719 /* try it as it came to us */
720 nt_status = password_check(username, password, crypted, salt);
721 if (NT_STATUS_IS_OK(nt_status)) {
725 else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
726 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
730 if ( user_info->flags | USER_INFO_CASE_INSENSITIVE_PASSWORD) {
734 /* if the password was given to us with mixed case then we don't
735 * need to proceed as we know it hasn't been case modified by the
737 if (strhasupper(password) && strhaslower(password)) {
741 /* make a copy of it */
742 pwcopy = talloc_strdup(ctx, password);
744 return NT_STATUS_NO_MEMORY;
746 /* try all lowercase if it's currently all uppercase */
747 if (strhasupper(pwcopy)) {
749 nt_status = password_check(username, pwcopy, crypted, salt);
750 if NT_STATUS_IS_OK(nt_status) {
758 return NT_STATUS_WRONG_PASSWORD;
761 /* last chance - all combinations of up to level chars upper! */
765 if (NT_STATUS_IS_OK(nt_status = string_combinations(pwcopy, password_check, level))) {
770 return NT_STATUS_WRONG_PASSWORD;
775 /** Check a plaintext username/password
779 static NTSTATUS authunix_want_check(struct auth_method_context *ctx,
781 const struct auth_usersupplied_info *user_info)
783 if (!user_info->mapped.account_name || !*user_info->mapped.account_name) {
784 return NT_STATUS_NOT_IMPLEMENTED;
790 static NTSTATUS authunix_check_password(struct auth_method_context *ctx,
792 const struct auth_usersupplied_info *user_info,
793 struct auth_serversupplied_info **server_info)
795 TALLOC_CTX *check_ctx;
799 if (user_info->password_state != AUTH_PASSWORD_PLAIN) {
800 return NT_STATUS_INVALID_PARAMETER;
803 check_ctx = talloc_named_const(mem_ctx, 0, "check_unix_password");
804 if (check_ctx == NULL) {
805 return NT_STATUS_NO_MEMORY;
808 nt_status = check_unix_password(check_ctx, ctx->auth_ctx->lp_ctx, user_info, &pwd);
809 if (!NT_STATUS_IS_OK(nt_status)) {
810 talloc_free(check_ctx);
814 nt_status = authunix_make_server_info(mem_ctx, lp_netbios_name(ctx->auth_ctx->lp_ctx),
815 user_info, pwd, server_info);
816 if (!NT_STATUS_IS_OK(nt_status)) {
817 talloc_free(check_ctx);
821 talloc_free(check_ctx);
825 static const struct auth_operations unix_ops = {
827 .get_challenge = auth_get_challenge_not_implemented,
828 .want_check = authunix_want_check,
829 .check_password = authunix_check_password
832 NTSTATUS auth_unix_init(void)
836 ret = auth_register(&unix_ops);
837 if (!NT_STATUS_IS_OK(ret)) {
838 DEBUG(0,("Failed to register unix auth backend!\n"));