s3: Fix a bad memleak in winbind
[Samba.git] / source4 / auth / ntlm / auth_unix.c
blob1717b9d0e180954caf1d85694bfd4c01b9c675e9
1 /*
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/>.
22 #include "includes.h"
23 #include "auth/auth.h"
24 #include "auth/ntlm/auth_proto.h"
25 #include "system/passwd.h" /* needed by some systems for struct passwd */
26 #include "lib/socket/socket.h"
27 #include "auth/ntlm/pam_errors.h"
28 #include "param/param.h"
30 /* TODO: look at how to best fill in parms retrieveing a struct passwd info
31 * except in case USER_INFO_DONT_CHECK_UNIX_ACCOUNT is set
33 static NTSTATUS authunix_make_server_info(TALLOC_CTX *mem_ctx,
34 const char *netbios_name,
35 const struct auth_usersupplied_info *user_info,
36 struct passwd *pwd,
37 struct auth_serversupplied_info **_server_info)
39 struct auth_serversupplied_info *server_info;
40 NTSTATUS status;
42 /* This is a real, real hack */
43 if (pwd->pw_uid == 0) {
44 status = auth_system_server_info(mem_ctx, netbios_name, &server_info);
45 if (!NT_STATUS_IS_OK(status)) {
46 return status;
49 server_info->account_name = talloc_steal(server_info, pwd->pw_name);
50 NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
52 server_info->domain_name = talloc_strdup(server_info, "unix");
53 NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
54 } else {
55 server_info = talloc(mem_ctx, struct auth_serversupplied_info);
56 NT_STATUS_HAVE_NO_MEMORY(server_info);
58 server_info->authenticated = true;
60 server_info->account_name = talloc_steal(server_info, pwd->pw_name);
61 NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
63 server_info->domain_name = talloc_strdup(server_info, "unix");
64 NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
66 /* This isn't in any way correct.. */
67 server_info->account_sid = NULL;
68 server_info->primary_group_sid = NULL;
69 server_info->n_domain_groups = 0;
70 server_info->domain_groups = NULL;
72 server_info->user_session_key = data_blob(NULL,0);
73 server_info->lm_session_key = data_blob(NULL,0);
75 server_info->full_name = talloc_steal(server_info, pwd->pw_gecos);
76 NT_STATUS_HAVE_NO_MEMORY(server_info->full_name);
77 server_info->logon_script = talloc_strdup(server_info, "");
78 NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script);
79 server_info->profile_path = talloc_strdup(server_info, "");
80 NT_STATUS_HAVE_NO_MEMORY(server_info->profile_path);
81 server_info->home_directory = talloc_strdup(server_info, "");
82 NT_STATUS_HAVE_NO_MEMORY(server_info->home_directory);
83 server_info->home_drive = talloc_strdup(server_info, "");
84 NT_STATUS_HAVE_NO_MEMORY(server_info->home_drive);
86 server_info->last_logon = 0;
87 server_info->last_logoff = 0;
88 server_info->acct_expiry = 0;
89 server_info->last_password_change = 0;
90 server_info->allow_password_change = 0;
91 server_info->force_password_change = 0;
92 server_info->logon_count = 0;
93 server_info->bad_password_count = 0;
94 server_info->acct_flags = 0;
96 *_server_info = server_info;
98 return NT_STATUS_OK;
101 static NTSTATUS talloc_getpwnam(TALLOC_CTX *ctx, const char *username, struct passwd **pws)
103 struct passwd *ret;
104 struct passwd *from;
106 *pws = NULL;
108 ret = talloc(ctx, struct passwd);
109 NT_STATUS_HAVE_NO_MEMORY(ret);
111 from = getpwnam(username);
112 if (!from) {
113 return NT_STATUS_NO_SUCH_USER;
116 ret->pw_name = talloc_strdup(ctx, from->pw_name);
117 NT_STATUS_HAVE_NO_MEMORY(ret->pw_name);
119 ret->pw_passwd = talloc_strdup(ctx, from->pw_passwd);
120 NT_STATUS_HAVE_NO_MEMORY(ret->pw_passwd);
122 ret->pw_uid = from->pw_uid;
123 ret->pw_gid = from->pw_gid;
124 ret->pw_gecos = talloc_strdup(ctx, from->pw_gecos);
125 NT_STATUS_HAVE_NO_MEMORY(ret->pw_gecos);
127 ret->pw_dir = talloc_strdup(ctx, from->pw_dir);
128 NT_STATUS_HAVE_NO_MEMORY(ret->pw_dir);
130 ret->pw_shell = talloc_strdup(ctx, from->pw_shell);
131 NT_STATUS_HAVE_NO_MEMORY(ret->pw_shell);
133 *pws = ret;
135 return NT_STATUS_OK;
139 #ifdef HAVE_SECURITY_PAM_APPL_H
140 #include <security/pam_appl.h>
142 struct smb_pam_user_info {
143 const char *account_name;
144 const char *plaintext_password;
147 #define COPY_STRING(s) (s) ? strdup(s) : NULL
150 * Check user password
151 * Currently it uses PAM only and fails on systems without PAM
152 * Samba3 code located in pass_check.c is to ugly to be used directly it will
153 * need major rework that's why pass_check.c is still there.
156 static int smb_pam_conv(int num_msg, const struct pam_message **msg,
157 struct pam_response **reply, void *appdata_ptr)
159 struct smb_pam_user_info *info = (struct smb_pam_user_info *)appdata_ptr;
160 int num;
162 if (num_msg <= 0) {
163 *reply = NULL;
164 return PAM_CONV_ERR;
168 * Apparantly HPUX has a buggy PAM that doesn't support the
169 * data pointer. Fail if this is the case. JRA.
172 if (info == NULL) {
173 *reply = NULL;
174 return PAM_CONV_ERR;
178 * PAM frees memory in reply messages by itself
179 * so use malloc instead of talloc here.
181 *reply = malloc_array_p(struct pam_response, num_msg);
182 if (*reply == NULL) {
183 return PAM_CONV_ERR;
186 for (num = 0; num < num_msg; num++) {
187 switch (msg[num]->msg_style) {
188 case PAM_PROMPT_ECHO_ON:
189 (*reply)[num].resp_retcode = PAM_SUCCESS;
190 (*reply)[num].resp = COPY_STRING(info->account_name);
191 break;
193 case PAM_PROMPT_ECHO_OFF:
194 (*reply)[num].resp_retcode = PAM_SUCCESS;
195 (*reply)[num].resp = COPY_STRING(info->plaintext_password);
196 break;
198 case PAM_TEXT_INFO:
199 (*reply)[num].resp_retcode = PAM_SUCCESS;
200 (*reply)[num].resp = NULL;
201 DEBUG(4,("PAM Info message in conversation function: %s\n", (msg[num]->msg)));
202 break;
204 case PAM_ERROR_MSG:
205 (*reply)[num].resp_retcode = PAM_SUCCESS;
206 (*reply)[num].resp = NULL;
207 DEBUG(4,("PAM Error message in conversation function: %s\n", (msg[num]->msg)));
208 break;
210 default:
211 while (num > 0) {
212 SAFE_FREE((*reply)[num-1].resp);
213 num--;
215 SAFE_FREE(*reply);
216 *reply = NULL;
217 DEBUG(1,("Error: PAM subsystme sent an UNKNOWN message type to the conversation function!\n"));
218 return PAM_CONV_ERR;
222 return PAM_SUCCESS;
226 * Start PAM authentication for specified account
229 static NTSTATUS smb_pam_start(pam_handle_t **pamh, const char *account_name, const char *remote_host, struct pam_conv *pconv)
231 int pam_error;
233 if (account_name == NULL || remote_host == NULL) {
234 return NT_STATUS_INVALID_PARAMETER;
237 DEBUG(4,("smb_pam_start: PAM: Init user: %s\n", account_name));
239 pam_error = pam_start("samba", account_name, pconv, pamh);
240 if (pam_error != PAM_SUCCESS) {
241 /* no valid pamh here, can we reliably call pam_strerror ? */
242 DEBUG(4,("smb_pam_start: pam_start failed!\n"));
243 return NT_STATUS_UNSUCCESSFUL;
246 #ifdef PAM_RHOST
247 DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", remote_host));
248 pam_error = pam_set_item(*pamh, PAM_RHOST, remote_host);
249 if (pam_error != PAM_SUCCESS) {
250 NTSTATUS nt_status;
252 DEBUG(4,("smb_pam_start: setting rhost failed with error: %s\n",
253 pam_strerror(*pamh, pam_error)));
254 nt_status = pam_to_nt_status(pam_error);
256 pam_error = pam_end(*pamh, 0);
257 if (pam_error != PAM_SUCCESS) {
258 /* no vaild pamh here, can we reliably call pam_strerror ? */
259 DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
260 pam_error));
261 return pam_to_nt_status(pam_error);
263 return nt_status;
265 #endif
266 #ifdef PAM_TTY
267 DEBUG(4,("smb_pam_start: PAM: setting tty\n"));
268 pam_error = pam_set_item(*pamh, PAM_TTY, "samba");
269 if (pam_error != PAM_SUCCESS) {
270 NTSTATUS nt_status;
272 DEBUG(4,("smb_pam_start: setting tty failed with error: %s\n",
273 pam_strerror(*pamh, pam_error)));
274 nt_status = pam_to_nt_status(pam_error);
276 pam_error = pam_end(*pamh, 0);
277 if (pam_error != PAM_SUCCESS) {
278 /* no vaild pamh here, can we reliably call pam_strerror ? */
279 DEBUG(4,("smb_pam_start: clean up failed, pam_end gave error %d.\n",
280 pam_error));
281 return pam_to_nt_status(pam_error);
283 return nt_status;
285 #endif
286 DEBUG(4,("smb_pam_start: PAM: Init passed for user: %s\n", account_name));
288 return NT_STATUS_OK;
291 static NTSTATUS smb_pam_end(pam_handle_t *pamh)
293 int pam_error;
295 if (pamh != NULL) {
296 pam_error = pam_end(pamh, 0);
297 if (pam_error != PAM_SUCCESS) {
298 /* no vaild pamh here, can we reliably call pam_strerror ? */
299 DEBUG(4,("smb_pam_end: clean up failed, pam_end gave error %d.\n",
300 pam_error));
301 return pam_to_nt_status(pam_error);
303 return NT_STATUS_OK;
306 DEBUG(2,("smb_pam_end: pamh is NULL, PAM not initialized ?\n"));
307 return NT_STATUS_UNSUCCESSFUL;
311 * PAM Authentication Handler
313 static NTSTATUS smb_pam_auth(pam_handle_t *pamh, bool allow_null_passwords, const char *user)
315 int pam_error;
318 * To enable debugging set in /etc/pam.d/samba:
319 * auth required /lib/security/pam_pwdb.so nullok shadow audit
322 DEBUG(4,("smb_pam_auth: PAM: Authenticate User: %s\n", user));
324 pam_error = pam_authenticate(pamh, PAM_SILENT | allow_null_passwords ? 0 : PAM_DISALLOW_NULL_AUTHTOK);
325 switch( pam_error ){
326 case PAM_AUTH_ERR:
327 DEBUG(2, ("smb_pam_auth: PAM: Authentication Error for user %s\n", user));
328 break;
329 case PAM_CRED_INSUFFICIENT:
330 DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user));
331 break;
332 case PAM_AUTHINFO_UNAVAIL:
333 DEBUG(2, ("smb_pam_auth: PAM: Authentication Information Unavailable for user %s\n", user));
334 break;
335 case PAM_USER_UNKNOWN:
336 DEBUG(2, ("smb_pam_auth: PAM: Username %s NOT known to Authentication system\n", user));
337 break;
338 case PAM_MAXTRIES:
339 DEBUG(2, ("smb_pam_auth: PAM: One or more authentication modules reports user limit for user %s exceeeded\n", user));
340 break;
341 case PAM_ABORT:
342 DEBUG(0, ("smb_pam_auth: PAM: One or more PAM modules failed to load for user %s\n", user));
343 break;
344 case PAM_SUCCESS:
345 DEBUG(4, ("smb_pam_auth: PAM: User %s Authenticated OK\n", user));
346 break;
347 default:
348 DEBUG(0, ("smb_pam_auth: PAM: UNKNOWN ERROR while authenticating user %s\n", user));
349 break;
352 return pam_to_nt_status(pam_error);
356 * PAM Account Handler
358 static NTSTATUS smb_pam_account(pam_handle_t *pamh, const char * user)
360 int pam_error;
362 DEBUG(4,("smb_pam_account: PAM: Account Management for User: %s\n", user));
364 pam_error = pam_acct_mgmt(pamh, PAM_SILENT); /* Is user account enabled? */
365 switch( pam_error ) {
366 case PAM_AUTHTOK_EXPIRED:
367 DEBUG(2, ("smb_pam_account: PAM: User %s is valid but password is expired\n", user));
368 break;
369 case PAM_ACCT_EXPIRED:
370 DEBUG(2, ("smb_pam_account: PAM: User %s no longer permitted to access system\n", user));
371 break;
372 case PAM_AUTH_ERR:
373 DEBUG(2, ("smb_pam_account: PAM: There was an authentication error for user %s\n", user));
374 break;
375 case PAM_PERM_DENIED:
376 DEBUG(0, ("smb_pam_account: PAM: User %s is NOT permitted to access system at this time\n", user));
377 break;
378 case PAM_USER_UNKNOWN:
379 DEBUG(0, ("smb_pam_account: PAM: User \"%s\" is NOT known to account management\n", user));
380 break;
381 case PAM_SUCCESS:
382 DEBUG(4, ("smb_pam_account: PAM: Account OK for User: %s\n", user));
383 break;
384 default:
385 DEBUG(0, ("smb_pam_account: PAM: UNKNOWN PAM ERROR (%d) during Account Management for User: %s\n", pam_error, user));
386 break;
389 return pam_to_nt_status(pam_error);
393 * PAM Credential Setting
396 static NTSTATUS smb_pam_setcred(pam_handle_t *pamh, const char * user)
398 int pam_error;
401 * This will allow samba to aquire a kerberos token. And, when
402 * exporting an AFS cell, be able to /write/ to this cell.
405 DEBUG(4,("PAM: Account Management SetCredentials for User: %s\n", user));
407 pam_error = pam_setcred(pamh, (PAM_ESTABLISH_CRED|PAM_SILENT));
408 switch( pam_error ) {
409 case PAM_CRED_UNAVAIL:
410 DEBUG(0, ("smb_pam_setcred: PAM: Credentials not found for user:%s\n", user ));
411 break;
412 case PAM_CRED_EXPIRED:
413 DEBUG(0, ("smb_pam_setcred: PAM: Credentials for user: \"%s\" EXPIRED!\n", user ));
414 break;
415 case PAM_USER_UNKNOWN:
416 DEBUG(0, ("smb_pam_setcred: PAM: User: \"%s\" is NOT known so can not set credentials!\n", user ));
417 break;
418 case PAM_CRED_ERR:
419 DEBUG(0, ("smb_pam_setcred: PAM: Unknown setcredentials error - unable to set credentials for %s\n", user ));
420 break;
421 case PAM_SUCCESS:
422 DEBUG(4, ("smb_pam_setcred: PAM: SetCredentials OK for User: %s\n", user));
423 break;
424 default:
425 DEBUG(0, ("smb_pam_setcred: PAM: UNKNOWN PAM ERROR (%d) during SetCredentials for User: %s\n", pam_error, user));
426 break;
429 return pam_to_nt_status(pam_error);
432 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, struct loadparm_context *lp_ctx,
433 const struct auth_usersupplied_info *user_info, struct passwd **pws)
435 struct smb_pam_user_info *info;
436 struct pam_conv *pamconv;
437 pam_handle_t *pamh;
438 NTSTATUS nt_status;
440 info = talloc(ctx, struct smb_pam_user_info);
441 if (info == NULL) {
442 return NT_STATUS_NO_MEMORY;
445 info->account_name = user_info->mapped.account_name;
446 info->plaintext_password = user_info->password.plaintext;
448 pamconv = talloc(ctx, struct pam_conv);
449 if (pamconv == NULL) {
450 return NT_STATUS_NO_MEMORY;
453 pamconv->conv = smb_pam_conv;
454 pamconv->appdata_ptr = (void *)info;
456 /* TODO:
457 * check for user_info->flags & USER_INFO_CASE_INSENSITIVE_USERNAME
458 * if true set up a crack name routine.
461 nt_status = smb_pam_start(&pamh, user_info->mapped.account_name, user_info->remote_host ? user_info->remote_host->addr : NULL, pamconv);
462 if (!NT_STATUS_IS_OK(nt_status)) {
463 return nt_status;
466 nt_status = smb_pam_auth(pamh, lp_null_passwords(lp_ctx), user_info->mapped.account_name);
467 if (!NT_STATUS_IS_OK(nt_status)) {
468 smb_pam_end(pamh);
469 return nt_status;
472 if ( ! (user_info->flags & USER_INFO_DONT_CHECK_UNIX_ACCOUNT)) {
474 nt_status = smb_pam_account(pamh, user_info->mapped.account_name);
475 if (!NT_STATUS_IS_OK(nt_status)) {
476 smb_pam_end(pamh);
477 return nt_status;
480 nt_status = smb_pam_setcred(pamh, user_info->mapped.account_name);
481 if (!NT_STATUS_IS_OK(nt_status)) {
482 smb_pam_end(pamh);
483 return nt_status;
487 smb_pam_end(pamh);
489 nt_status = talloc_getpwnam(ctx, user_info->mapped.account_name, pws);
490 if (!NT_STATUS_IS_OK(nt_status)) {
491 return nt_status;
494 return NT_STATUS_OK;
497 #else
499 /****************************************************************************
500 core of password checking routine
501 ****************************************************************************/
502 static NTSTATUS password_check(const char *username, const char *password,
503 const char *crypted, const char *salt)
505 bool ret;
507 #ifdef WITH_AFS
508 if (afs_auth(username, password))
509 return NT_STATUS_OK;
510 #endif /* WITH_AFS */
512 #ifdef WITH_DFS
513 if (dfs_auth(username, password))
514 return NT_STATUS_OK;
515 #endif /* WITH_DFS */
517 #ifdef OSF1_ENH_SEC
519 ret = (strcmp(osf1_bigcrypt(password, salt), crypted) == 0);
521 if (!ret) {
522 DEBUG(2,
523 ("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
524 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
526 if (ret) {
527 return NT_STATUS_OK;
528 } else {
529 return NT_STATUS_WRONG_PASSWORD;
532 #endif /* OSF1_ENH_SEC */
534 #ifdef ULTRIX_AUTH
535 ret = (strcmp((char *)crypt16(password, salt), crypted) == 0);
536 if (ret) {
537 return NT_STATUS_OK;
538 } else {
539 return NT_STATUS_WRONG_PASSWORD;
542 #endif /* ULTRIX_AUTH */
544 #ifdef LINUX_BIGCRYPT
545 ret = (linux_bigcrypt(password, salt, crypted));
546 if (ret) {
547 return NT_STATUS_OK;
548 } else {
549 return NT_STATUS_WRONG_PASSWORD;
551 #endif /* LINUX_BIGCRYPT */
553 #if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
556 * Some systems have bigcrypt in the C library but might not
557 * actually use it for the password hashes (HPUX 10.20) is
558 * a noteable example. So we try bigcrypt first, followed
559 * by crypt.
562 if (strcmp(bigcrypt(password, salt), crypted) == 0)
563 return NT_STATUS_OK;
564 else
565 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
566 if (ret) {
567 return NT_STATUS_OK;
568 } else {
569 return NT_STATUS_WRONG_PASSWORD;
571 #else /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
573 #ifdef HAVE_BIGCRYPT
574 ret = (strcmp(bigcrypt(password, salt), crypted) == 0);
575 if (ret) {
576 return NT_STATUS_OK;
577 } else {
578 return NT_STATUS_WRONG_PASSWORD;
580 #endif /* HAVE_BIGCRYPT */
582 #ifndef HAVE_CRYPT
583 DEBUG(1, ("Warning - no crypt available\n"));
584 return NT_STATUS_LOGON_FAILURE;
585 #else /* HAVE_CRYPT */
586 ret = (strcmp((char *)crypt(password, salt), crypted) == 0);
587 if (ret) {
588 return NT_STATUS_OK;
589 } else {
590 return NT_STATUS_WRONG_PASSWORD;
592 #endif /* HAVE_CRYPT */
593 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
596 static NTSTATUS check_unix_password(TALLOC_CTX *ctx, struct loadparm_context *lp_ctx,
597 const struct auth_usersupplied_info *user_info, struct passwd **ret_passwd)
599 char *username;
600 char *password;
601 char *pwcopy;
602 char *salt;
603 char *crypted;
604 struct passwd *pws;
605 NTSTATUS nt_status;
606 int level = lp_passwordlevel(lp_ctx);
608 *ret_passwd = NULL;
610 username = talloc_strdup(ctx, user_info->mapped.account_name);
611 password = talloc_strdup(ctx, user_info->password.plaintext);
613 nt_status = talloc_getpwnam(ctx, username, &pws);
614 if (!NT_STATUS_IS_OK(nt_status)) {
615 return nt_status;
618 crypted = pws->pw_passwd;
619 salt = pws->pw_passwd;
621 #ifdef HAVE_GETSPNAM
623 struct spwd *spass;
625 /* many shadow systems require you to be root to get
626 the password, in most cases this should already be
627 the case when this function is called, except
628 perhaps for IPC password changing requests */
630 spass = getspnam(pws->pw_name);
631 if (spass && spass->sp_pwdp) {
632 crypted = talloc_strdup(ctx, spass->sp_pwdp);
633 NT_STATUS_HAVE_NO_MEMORY(crypted);
634 salt = talloc_strdup(ctx, spass->sp_pwdp);
635 NT_STATUS_HAVE_NO_MEMORY(salt);
638 #elif defined(IA_UINFO)
640 char *ia_password;
641 /* Need to get password with SVR4.2's ia_ functions
642 instead of get{sp,pw}ent functions. Required by
643 UnixWare 2.x, tested on version
644 2.1. (tangent@cyberport.com) */
645 uinfo_t uinfo;
646 if (ia_openinfo(pws->pw_name, &uinfo) != -1) {
647 ia_get_logpwd(uinfo, &ia_password);
648 crypted = talloc_strdup(ctx, ia_password);
649 NT_STATUS_HAVE_NO_MEMORY(crypted);
652 #endif
654 #ifdef HAVE_GETPRPWNAM
656 struct pr_passwd *pr_pw = getprpwnam(pws->pw_name);
657 if (pr_pw && pr_pw->ufld.fd_encrypt) {
658 crypted = talloc_strdup(ctx, pr_pw->ufld.fd_encrypt);
659 NT_STATUS_HAVE_NO_MEMORY(crypted);
662 #endif
664 #ifdef HAVE_GETPWANAM
666 struct passwd_adjunct *pwret;
667 pwret = getpwanam(s);
668 if (pwret && pwret->pwa_passwd) {
669 crypted = talloc_strdup(ctx, pwret->pwa_passwd);
670 NT_STATUS_HAVE_NO_MEMORY(crypted);
673 #endif
675 #ifdef OSF1_ENH_SEC
677 struct pr_passwd *mypasswd;
678 DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n", username));
679 mypasswd = getprpwnam(username);
680 if (mypasswd) {
681 username = talloc_strdup(ctx, mypasswd->ufld.fd_name);
682 NT_STATUS_HAVE_NO_MEMORY(username);
683 crypted = talloc_strdup(ctx, mypasswd->ufld.fd_encrypt);
684 NT_STATUS_HAVE_NO_MEMORY(crypted);
685 } else {
686 DEBUG(5,("OSF1_ENH_SEC: No entry for user %s in protected database !\n", username));
689 #endif
691 #ifdef ULTRIX_AUTH
693 AUTHORIZATION *ap = getauthuid(pws->pw_uid);
694 if (ap) {
695 crypted = talloc_strdup(ctx, ap->a_password);
696 endauthent();
697 NT_STATUS_HAVE_NO_MEMORY(crypted);
700 #endif
702 #if defined(HAVE_TRUNCATED_SALT)
703 /* crypt on some platforms (HPUX in particular)
704 won't work with more than 2 salt characters. */
705 salt[2] = 0;
706 #endif
708 if (crypted[0] == '\0') {
709 if (!lp_null_passwords(lp_ctx)) {
710 DEBUG(2, ("Disallowing %s with null password\n", username));
711 return NT_STATUS_LOGON_FAILURE;
713 if (password == NULL) {
714 DEBUG(3, ("Allowing access to %s with null password\n", username));
715 *ret_passwd = pws;
716 return NT_STATUS_OK;
720 /* try it as it came to us */
721 nt_status = password_check(username, password, crypted, salt);
722 if (NT_STATUS_IS_OK(nt_status)) {
723 *ret_passwd = pws;
724 return nt_status;
726 else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
727 /* No point continuing if its not the password thats to blame (ie PAM disabled). */
728 return nt_status;
731 if ( user_info->flags | USER_INFO_CASE_INSENSITIVE_PASSWORD) {
732 return nt_status;
735 /* if the password was given to us with mixed case then we don't
736 * need to proceed as we know it hasn't been case modified by the
737 * client */
738 if (strhasupper(password) && strhaslower(password)) {
739 return nt_status;
742 /* make a copy of it */
743 pwcopy = talloc_strdup(ctx, password);
744 if (!pwcopy)
745 return NT_STATUS_NO_MEMORY;
747 /* try all lowercase if it's currently all uppercase */
748 if (strhasupper(pwcopy)) {
749 strlower(pwcopy);
750 nt_status = password_check(username, pwcopy, crypted, salt);
751 if NT_STATUS_IS_OK(nt_status) {
752 *ret_passwd = pws;
753 return nt_status;
757 /* give up? */
758 if (level < 1) {
759 return NT_STATUS_WRONG_PASSWORD;
762 /* last chance - all combinations of up to level chars upper! */
763 strlower(pwcopy);
765 #if 0
766 if (NT_STATUS_IS_OK(nt_status = string_combinations(pwcopy, password_check, level))) {
767 *ret_passwd = pws;
768 return nt_status;
770 #endif
771 return NT_STATUS_WRONG_PASSWORD;
774 #endif
776 /** Check a plaintext username/password
780 static NTSTATUS authunix_want_check(struct auth_method_context *ctx,
781 TALLOC_CTX *mem_ctx,
782 const struct auth_usersupplied_info *user_info)
784 if (!user_info->mapped.account_name || !*user_info->mapped.account_name) {
785 return NT_STATUS_NOT_IMPLEMENTED;
788 return NT_STATUS_OK;
791 static NTSTATUS authunix_check_password(struct auth_method_context *ctx,
792 TALLOC_CTX *mem_ctx,
793 const struct auth_usersupplied_info *user_info,
794 struct auth_serversupplied_info **server_info)
796 TALLOC_CTX *check_ctx;
797 NTSTATUS nt_status;
798 struct passwd *pwd;
800 if (user_info->password_state != AUTH_PASSWORD_PLAIN) {
801 return NT_STATUS_INVALID_PARAMETER;
804 check_ctx = talloc_named_const(mem_ctx, 0, "check_unix_password");
805 if (check_ctx == NULL) {
806 return NT_STATUS_NO_MEMORY;
809 nt_status = check_unix_password(check_ctx, ctx->auth_ctx->lp_ctx, user_info, &pwd);
810 if (!NT_STATUS_IS_OK(nt_status)) {
811 talloc_free(check_ctx);
812 return nt_status;
815 nt_status = authunix_make_server_info(mem_ctx, lp_netbios_name(ctx->auth_ctx->lp_ctx),
816 user_info, pwd, server_info);
817 if (!NT_STATUS_IS_OK(nt_status)) {
818 talloc_free(check_ctx);
819 return nt_status;
822 talloc_free(check_ctx);
823 return NT_STATUS_OK;
826 static const struct auth_operations unix_ops = {
827 .name = "unix",
828 .get_challenge = auth_get_challenge_not_implemented,
829 .want_check = authunix_want_check,
830 .check_password = authunix_check_password
833 _PUBLIC_ NTSTATUS auth_unix_init(void)
835 NTSTATUS ret;
837 ret = auth_register(&unix_ops);
838 if (!NT_STATUS_IS_OK(ret)) {
839 DEBUG(0,("Failed to register unix auth backend!\n"));
840 return ret;
843 return ret;